From af4fe2493925bc57c5c3343c383719fa72dea262 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Wed, 11 Jan 2017 16:50:38 -0500 Subject: [PATCH] Squashed 'src/beast/' changes from 2f9a844..1ab7a2f 1ab7a2f Set version to 1.0.0-b22 2eb4b0c Fix code sample in websocket.qbk 58802f4 Fix typos in design.qbk 19dc4bb Update documentation examples 10dbc5b Disable Boost.Coroutine deprecation warning 01c76c7 Fix websocket stream read documentation d152c96 Update README.md example programs 995d86f Avoid copies in handler_alloc 851cb62 Add handler helpers 114175c Implement asio dealloc-before-invoke guarantee: 681db2e Add missing include 7db3c6e Fix broken Intellisense (MSVC) 09c183d Set version to 1.0.0-b21 1cb01fe Remove extraneous includes 62e65ed Set version to 1.0.0-b20 45eaa8c Increase utf8 checker code coverage 9ff1a27 Add zlib module: a0a3359 Refactor HTTP identifier names (API Change): 79be7f8 Set version to 1.0.0-b19 eda1120 Tidy up internal name 4130ad4 Better buffer_cat: f94f21d Fix consuming_buffers value_type (API Change): 2c524b4 prepared_buffers is private (API Change) df2a108 Fix prepare_buffers value_type: a4af9d6 Use boost::lexical_cast instead of std::to_string 62d670b Fix with_body example: a63bd84 Increase code coverage 84a6775 Boost library min/max guidance: 02feea5 Add read, async_read for message_headers: f224585 Add write, async_write, operator<< for message_headers: ea48bcf Make chunk_encode public: f6dd744 Refactor message and message_headers declarations: 9fd8aed Move sync_ostream to core/detail c98b2d3 Optimize mask operations d4dfc1a Optimize utf8 validation 7b4de4b Set version to 1.0.0-b18 feb5204 Add websocket::stream pong and async_pong d4ffde5 Close connection during async_read on close frame: 644d518 Move clamp to core 427ba38 Fix write_frame masking and auto-fragment handling 54a51b1 Write buffer option does not change capacity 591dbc0 Meet DynamicBuffer requirements for static_streambuf 46d5e72 Reorganize source files and definitions efa4b8f Override incremental link flags: eef6e86 Higher optimization settings for MSVC builds b6f3a36 Check invariants in parse_op: 47b0fa6 Remove unused field in test 8b8e57e unit_test improvements: e907252 Clean up message docs 1e3543f Set version to 1.0.0-b17 de97a69 Trim unused code 796b484 Doc fixes 95c37e2 Fix unused parameter warnings and missing includes: 8b0d285 Refactor read_size_helper 97a9dcb Improve websocket example in README.md 236caef Engaged invokable is destructible: d107ba1 Add headers_parser: 2f90627 Fix handling of body_what::pause in basic_parser_v1 9353d04 Add basic_parser_v1::reset 658e03c Add on_body_what parser callback (API Change): 50bd446 Fix parser traits detection (API Change): df8d306 Tidy up documentation: 47105f8 Tidy up basic_headers for documentation ada1f60 Refine message class hierarchy: cf43f51 Rework HTTP concepts (API Change): 8a261ca HTTP Reader (API Change): 183055a Parser callbacks may not throw (API Change) ebebe52 Add basic_streambuf::alloc_size c9cd171 Fix basic_streambuf::capacity 0eb0e48 Tidying: c5c436d Change implicit_value to default_value 01f939d Set version to 1.0.0-b16 206d0a9 Fix websocket failure tests 6b4fb28 Fix Writer exemplar in docs 4224a3a Relax ForwardIterator requirements in FieldSequence 14d7f8d Refactor base_parser_v1 callback traits: d812344 Add pause option to on_headers interface: c59bd53 Improve first line serialization 78ff20b Constrain parser_v1 constructor 2765a67 Refine Parser concept: c329d33 Fix on_headers called twice from basic_parser_v1 55c4c93 Put back missing Design section in docs 90cec54 Make auto_fragment a boolean option 03642fb Rename to write_buffer_size 0ca8964 Frame processing routines are member functions d99dfb3 Make value optional in param-list 325f579 Set version to 1.0.0-b15 c54762a Fix handling empty HTTP headers in parser_v1.hpp c39cc06 Regression test for empty headers 60e637b Tidy up error types: d54d597 Tidy up DynamicBuffer requirements 707fb5e Fix doc reference section 38af0f7 Fix message_v1 constructor 027c4e8 Add Secure WebSocket example 5baaa49 Add HTTPS example 076456b rfc7230 section 3.3.2 compliance a09a044 Use bin/sh 1ff192d Update README.md for CppCon 2016 presentation 70b8555 Set version to 1.0.0-b14 b4a8342 Update and tidy documentation 8607af5 Update README.md 4abb43e Use BOOST_ASSERT b5bffee Don't rely on undefined behavior 8ee7a21 Better WebSocket decorator: 38f0d95 Update build scripts for MSVC, MinGW 2a5b116 Fix error handling in server examples 4c7065a Add missing rebind to handler_alloc git-subtree-dir: src/beast git-subtree-split: 1ab7a2f04ca9a0b35f2032877cab78d94e96ebad --- .travis.yml | 4 +- CHANGELOG.md | 180 + CMakeLists.txt | 46 +- Jamroot | 19 +- README.md | 32 +- TODO.txt | 2 + doc/{Jamfile => Jamfile.v2} | 76 +- doc/design.qbk | 198 +- doc/examples.qbk | 127 + doc/http.qbk | 481 +-- doc/images/CppCon2016.pdf | Bin 0 -> 475799 bytes doc/images/CppCon2016.png | Bin 0 -> 81947 bytes doc/images/beast.png | Bin 247196 -> 148154 bytes doc/images/beast.psd | Bin 28626252 -> 28419622 bytes doc/images/message.png | Bin 9532 -> 30460 bytes doc/images/message.psd | Bin 204871 -> 378966 bytes doc/index.xml | 3 +- doc/makeqbk.sh | 2 +- doc/master.qbk | 235 +- doc/overview.qbk | 114 + doc/quickref.xml | 139 +- doc/reference.xsl | 80 +- doc/source.dox | 48 +- doc/types/Body.qbk | 15 +- doc/types/BufferSequence.qbk | 2 +- doc/types/DynamicBuffer.qbk | 6 +- doc/types/Field.qbk | 2 +- doc/types/FieldSequence.qbk | 27 +- doc/types/Parser.qbk | 33 +- doc/types/Reader.qbk | 47 +- doc/types/Streams.qbk | 2 +- doc/types/Writer.qbk | 64 +- doc/websocket.qbk | 245 +- examples/{Jamfile => Jamfile.v2} | 3 - examples/file_body.hpp | 18 +- examples/http_async_server.hpp | 89 +- examples/http_crawl.cpp | 13 +- examples/http_example.cpp | 10 +- examples/http_server.cpp | 24 +- examples/http_sync_server.hpp | 45 +- examples/ssl/CMakeLists.txt | 32 + examples/ssl/Jamfile.v2 | 54 + examples/ssl/http_ssl_example.cpp | 58 + examples/ssl/websocket_ssl_example.cpp | 49 + examples/websocket_example.cpp | 4 +- {include => extras}/beast/doc_debug.hpp | 0 extras/beast/test/fail_counter.hpp | 15 +- extras/beast/test/string_stream.hpp | 1 + extras/beast/unit_test/reporter.hpp | 4 +- extras/beast/unit_test/runner.hpp | 8 +- extras/beast/unit_test/suite.hpp | 75 +- extras/beast/unit_test/suite_list.hpp | 6 +- include/beast/core.hpp | 2 + include/beast/core/async_completion.hpp | 4 +- include/beast/core/basic_streambuf.hpp | 34 +- include/beast/core/buffer_cat.hpp | 28 +- include/beast/core/consuming_buffers.hpp | 38 +- include/beast/core/detail/bind_handler.hpp | 12 +- include/beast/core/detail/buffer_cat.hpp | 219 +- include/beast/core/detail/buffer_concepts.hpp | 74 +- include/beast/core/detail/clamp.hpp | 40 + .../beast/core/detail/is_call_possible.hpp | 3 + .../prepare_buffers.hpp} | 190 +- include/beast/core/detail/sha1.hpp | 2 +- include/beast/core/detail/stream_concepts.hpp | 10 +- include/beast/core/detail/sync_ostream.hpp | 93 + include/beast/core/detail/type_traits.hpp | 84 + include/beast/core/dynabuf_readstream.hpp | 5 +- include/beast/core/error.hpp | 12 + include/beast/core/handler_alloc.hpp | 43 +- include/beast/core/handler_helpers.hpp | 104 + include/beast/core/handler_ptr.hpp | 173 + include/beast/core/impl/basic_streambuf.ipp | 51 +- include/beast/core/impl/buffers_adapter.ipp | 2 +- include/beast/core/impl/consuming_buffers.ipp | 70 +- .../beast/core/impl/dynabuf_readstream.ipp | 38 +- include/beast/core/impl/handler_ptr.ipp | 138 + include/beast/core/impl/static_streambuf.ipp | 19 +- include/beast/core/prepare_buffer.hpp | 68 + include/beast/core/prepare_buffers.hpp | 147 +- include/beast/core/static_streambuf.hpp | 41 +- include/beast/http.hpp | 8 +- include/beast/http/basic_dynabuf_body.hpp | 34 +- include/beast/http/basic_fields.hpp | 306 ++ include/beast/http/basic_headers.hpp | 474 --- include/beast/http/basic_parser_v1.hpp | 769 ++--- include/beast/http/body_type.hpp | 19 - include/beast/http/chunk_encode.hpp | 74 + include/beast/http/concepts.hpp | 235 +- include/beast/http/detail/basic_fields.hpp | 214 ++ include/beast/http/detail/basic_parser_v1.hpp | 4 +- include/beast/http/detail/chunk_encode.hpp | 85 +- .../beast/http/detail/has_content_length.hpp | 43 - include/beast/http/detail/rfc7230.hpp | 84 +- include/beast/http/empty_body.hpp | 26 +- .../beast/http/{headers.hpp => fields.hpp} | 11 +- include/beast/http/header_parser_v1.hpp | 232 ++ .../{basic_headers.ipp => basic_fields.ipp} | 120 +- include/beast/http/impl/basic_parser_v1.ipp | 152 +- include/beast/http/impl/message.ipp | 264 ++ include/beast/http/impl/message_v1.ipp | 188 -- include/beast/http/impl/parse.ipp | 303 ++ include/beast/http/impl/parse_error.ipp | 105 + include/beast/http/impl/read.ipp | 547 ++- include/beast/http/impl/rfc7230.ipp | 75 +- include/beast/http/impl/write.ipp | 446 ++- include/beast/http/message.hpp | 424 ++- include/beast/http/message_v1.hpp | 135 - include/beast/http/parse.hpp | 154 + include/beast/http/parse_error.hpp | 137 +- include/beast/http/parser_v1.hpp | 230 +- include/beast/http/read.hpp | 361 +- include/beast/http/reason.hpp | 13 +- include/beast/http/rfc7230.hpp | 75 +- include/beast/http/string_body.hpp | 34 +- include/beast/http/write.hpp | 196 +- include/beast/version.hpp | 2 +- include/beast/websocket/detail/decorator.hpp | 78 +- include/beast/websocket/detail/error.hpp | 92 - include/beast/websocket/detail/frame.hpp | 144 +- include/beast/websocket/detail/hybi13.hpp | 19 +- include/beast/websocket/detail/invokable.hpp | 30 +- include/beast/websocket/detail/mask.hpp | 126 +- .../beast/websocket/detail/stream_base.hpp | 457 ++- .../beast/websocket/detail/utf8_checker.hpp | 299 +- include/beast/websocket/error.hpp | 11 +- include/beast/websocket/impl/accept.ipp | 423 +++ include/beast/websocket/impl/accept_op.ipp | 154 - .../impl/{close_op.ipp => close.ipp} | 92 +- include/beast/websocket/impl/error.ipp | 81 +- .../impl/{handshake_op.ipp => handshake.ipp} | 109 +- .../websocket/impl/{ping_op.ipp => ping.ipp} | 136 +- .../impl/{read_frame_op.ipp => read.ipp} | 442 ++- include/beast/websocket/impl/read_op.ipp | 142 - include/beast/websocket/impl/response_op.ipp | 139 - include/beast/websocket/impl/ssl.ipp | 37 +- include/beast/websocket/impl/stream.ipp | 922 +---- include/beast/websocket/impl/teardown.ipp | 39 +- include/beast/websocket/impl/write.ipp | 683 ++++ .../beast/websocket/impl/write_frame_op.ipp | 282 -- include/beast/websocket/impl/write_op.ipp | 140 - include/beast/websocket/option.hpp | 166 +- include/beast/websocket/stream.hpp | 286 +- include/beast/websocket/teardown.hpp | 9 +- include/beast/zlib.hpp | 14 + include/beast/zlib/deflate_stream.hpp | 398 +++ include/beast/zlib/detail/bitstream.hpp | 203 ++ include/beast/zlib/detail/deflate_stream.hpp | 2979 +++++++++++++++++ include/beast/zlib/detail/inflate_stream.hpp | 1302 +++++++ include/beast/zlib/detail/ranges.hpp | 100 + include/beast/zlib/detail/window.hpp | 161 + include/beast/zlib/error.hpp | 133 + include/beast/zlib/impl/error.ipp | 137 + include/beast/zlib/inflate_stream.hpp | 214 ++ include/beast/zlib/zlib.hpp | 178 + index.html | 20 + scripts/build-and-test.sh | 2 +- scripts/valgrind.supp | 10 + test/CMakeLists.txt | 5 + test/Jamfile | 30 +- test/core/CMakeLists.txt | 3 + test/core/basic_streambuf.cpp | 36 +- test/core/buffer_cat.cpp | 128 +- .../stream_base.cpp => core/clamp.cpp} | 15 +- test/core/consuming_buffers.cpp | 10 + test/core/dynabuf_readstream.cpp | 8 +- test/core/handler_ptr.cpp | 9 + test/core/prepare_buffers.cpp | 55 + test/core/streambuf.cpp | 7 + test/core/zlib.cpp | 232 ++ test/http/CMakeLists.txt | 8 +- .../{basic_headers.cpp => basic_fields.cpp} | 15 +- test/http/basic_parser_v1.cpp | 65 +- test/http/chunk_encode.cpp | 18 +- test/http/fail_parser.hpp | 16 +- test/http/{headers.cpp => fields.cpp} | 2 +- test/http/header_parser_v1.cpp | 90 + test/http/message.cpp | 195 +- test/http/message_fuzz.hpp | 9 +- test/http/message_v1.cpp | 119 - test/http/nodejs_parser.hpp | 24 +- test/http/{body_type.cpp => parse.cpp} | 2 +- test/http/parse_error.cpp | 19 +- test/http/parser_bench.cpp | 8 +- test/http/parser_v1.cpp | 81 +- test/http/read.cpp | 141 +- test/http/rfc7230.cpp | 23 +- test/http/streambuf_body.cpp | 4 +- test/http/write.cpp | 192 +- test/websocket/CMakeLists.txt | 5 +- test/websocket/error.cpp | 10 +- test/websocket/frame.cpp | 41 +- test/websocket/stream.cpp | 83 +- test/websocket/utf8_checker.cpp | 149 +- .../websocket/websocket_async_echo_server.hpp | 15 +- test/websocket/websocket_sync_echo_server.hpp | 18 +- test/zlib.cpp | 9 + test/zlib/CMakeLists.txt | 47 + test/zlib/deflate_stream.cpp | 336 ++ test/zlib/error.cpp | 61 + test/zlib/inflate_stream.cpp | 412 +++ test/zlib/zlib-1.2.8/CMakeLists.txt | 249 ++ test/zlib/zlib-1.2.8/ChangeLog | 1472 ++++++++ test/zlib/zlib-1.2.8/FAQ | 368 ++ test/zlib/zlib-1.2.8/INDEX | 68 + test/zlib/zlib-1.2.8/Makefile | 5 + test/zlib/zlib-1.2.8/Makefile.in | 288 ++ test/zlib/zlib-1.2.8/README | 115 + test/zlib/zlib-1.2.8/adler32.c | 179 + test/zlib/zlib-1.2.8/amiga/Makefile.pup | 69 + test/zlib/zlib-1.2.8/amiga/Makefile.sas | 68 + test/zlib/zlib-1.2.8/as400/bndsrc | 215 ++ test/zlib/zlib-1.2.8/as400/compile.clp | 110 + test/zlib/zlib-1.2.8/as400/readme.txt | 115 + test/zlib/zlib-1.2.8/as400/zlib.inc | 451 +++ test/zlib/zlib-1.2.8/compress.c | 80 + test/zlib/zlib-1.2.8/configure | 831 +++++ test/zlib/zlib-1.2.8/contrib/README.contrib | 78 + .../zlib-1.2.8/contrib/ada/buffer_demo.adb | 106 + test/zlib/zlib-1.2.8/contrib/ada/mtest.adb | 156 + test/zlib/zlib-1.2.8/contrib/ada/read.adb | 156 + test/zlib/zlib-1.2.8/contrib/ada/readme.txt | 65 + test/zlib/zlib-1.2.8/contrib/ada/test.adb | 463 +++ .../zlib-1.2.8/contrib/ada/zlib-streams.adb | 225 ++ .../zlib-1.2.8/contrib/ada/zlib-streams.ads | 114 + .../zlib/zlib-1.2.8/contrib/ada/zlib-thin.adb | 141 + .../zlib/zlib-1.2.8/contrib/ada/zlib-thin.ads | 450 +++ test/zlib/zlib-1.2.8/contrib/ada/zlib.adb | 701 ++++ test/zlib/zlib-1.2.8/contrib/ada/zlib.ads | 328 ++ test/zlib/zlib-1.2.8/contrib/ada/zlib.gpr | 20 + .../zlib-1.2.8/contrib/amd64/amd64-match.S | 452 +++ .../zlib/zlib-1.2.8/contrib/asm686/README.686 | 51 + test/zlib/zlib-1.2.8/contrib/asm686/match.S | 357 ++ test/zlib/zlib-1.2.8/contrib/blast/Makefile | 8 + test/zlib/zlib-1.2.8/contrib/blast/README | 4 + test/zlib/zlib-1.2.8/contrib/blast/blast.c | 446 +++ test/zlib/zlib-1.2.8/contrib/blast/blast.h | 75 + test/zlib/zlib-1.2.8/contrib/blast/test.pk | Bin 0 -> 8 bytes test/zlib/zlib-1.2.8/contrib/blast/test.txt | 1 + test/zlib/zlib-1.2.8/contrib/delphi/ZLib.pas | 557 +++ .../zlib-1.2.8/contrib/delphi/ZLibConst.pas | 11 + .../zlib/zlib-1.2.8/contrib/delphi/readme.txt | 76 + .../zlib-1.2.8/contrib/delphi/zlibd32.mak | 99 + .../zlib-1.2.8/contrib/dotzlib/DotZLib.build | 33 + .../zlib-1.2.8/contrib/dotzlib/DotZLib.chm | Bin 0 -> 72726 bytes .../zlib-1.2.8/contrib/dotzlib/DotZLib.sln | 21 + .../contrib/dotzlib/DotZLib/AssemblyInfo.cs | 58 + .../contrib/dotzlib/DotZLib/ChecksumImpl.cs | 202 ++ .../contrib/dotzlib/DotZLib/CircularBuffer.cs | 83 + .../contrib/dotzlib/DotZLib/CodecBase.cs | 198 ++ .../contrib/dotzlib/DotZLib/Deflater.cs | 106 + .../contrib/dotzlib/DotZLib/DotZLib.cs | 288 ++ .../contrib/dotzlib/DotZLib/DotZLib.csproj | 141 + .../contrib/dotzlib/DotZLib/GZipStream.cs | 301 ++ .../contrib/dotzlib/DotZLib/Inflater.cs | 105 + .../contrib/dotzlib/DotZLib/UnitTests.cs | 274 ++ .../contrib/dotzlib/LICENSE_1_0.txt | 23 + .../zlib-1.2.8/contrib/dotzlib/readme.txt | 58 + .../zlib-1.2.8/contrib/gcc_gvmat64/gvmat64.S | 574 ++++ test/zlib/zlib-1.2.8/contrib/infback9/README | 1 + .../zlib-1.2.8/contrib/infback9/infback9.c | 615 ++++ .../zlib-1.2.8/contrib/infback9/infback9.h | 37 + .../zlib-1.2.8/contrib/infback9/inffix9.h | 107 + .../zlib-1.2.8/contrib/infback9/inflate9.h | 47 + .../zlib-1.2.8/contrib/infback9/inftree9.c | 324 ++ .../zlib-1.2.8/contrib/infback9/inftree9.h | 61 + .../zlib-1.2.8/contrib/inflate86/inffas86.c | 1157 +++++++ .../zlib-1.2.8/contrib/inflate86/inffast.S | 1368 ++++++++ .../zlib/zlib-1.2.8/contrib/iostream/test.cpp | 24 + .../zlib-1.2.8/contrib/iostream/zfstream.cpp | 329 ++ .../zlib-1.2.8/contrib/iostream/zfstream.h | 128 + .../zlib-1.2.8/contrib/iostream2/zstream.h | 307 ++ .../contrib/iostream2/zstream_test.cpp | 25 + test/zlib/zlib-1.2.8/contrib/iostream3/README | 35 + test/zlib/zlib-1.2.8/contrib/iostream3/TODO | 17 + .../zlib/zlib-1.2.8/contrib/iostream3/test.cc | 50 + .../zlib-1.2.8/contrib/iostream3/zfstream.cc | 479 +++ .../zlib-1.2.8/contrib/iostream3/zfstream.h | 466 +++ .../zlib-1.2.8/contrib/masmx64/bld_ml64.bat | 2 + .../zlib-1.2.8/contrib/masmx64/gvmat64.asm | 553 +++ .../zlib-1.2.8/contrib/masmx64/inffas8664.c | 186 + .../zlib-1.2.8/contrib/masmx64/inffasx64.asm | 396 +++ .../zlib-1.2.8/contrib/masmx64/readme.txt | 31 + .../zlib-1.2.8/contrib/masmx86/bld_ml32.bat | 2 + .../zlib-1.2.8/contrib/masmx86/inffas32.asm | 1080 ++++++ .../zlib-1.2.8/contrib/masmx86/match686.asm | 479 +++ .../zlib-1.2.8/contrib/masmx86/readme.txt | 27 + test/zlib/zlib-1.2.8/contrib/minizip/Makefile | 25 + .../zlib-1.2.8/contrib/minizip/Makefile.am | 45 + .../contrib/minizip/MiniZip64_Changes.txt | 6 + .../contrib/minizip/MiniZip64_info.txt | 74 + .../zlib-1.2.8/contrib/minizip/configure.ac | 32 + test/zlib/zlib-1.2.8/contrib/minizip/crypt.h | 131 + test/zlib/zlib-1.2.8/contrib/minizip/ioapi.c | 247 ++ test/zlib/zlib-1.2.8/contrib/minizip/ioapi.h | 208 ++ .../zlib/zlib-1.2.8/contrib/minizip/iowin32.c | 461 +++ .../zlib/zlib-1.2.8/contrib/minizip/iowin32.h | 28 + .../zlib-1.2.8/contrib/minizip/make_vms.com | 25 + .../zlib/zlib-1.2.8/contrib/minizip/miniunz.c | 660 ++++ .../zlib-1.2.8/contrib/minizip/miniunzip.1 | 63 + .../zlib/zlib-1.2.8/contrib/minizip/minizip.1 | 46 + .../zlib/zlib-1.2.8/contrib/minizip/minizip.c | 520 +++ .../zlib-1.2.8/contrib/minizip/minizip.pc.in | 12 + .../zlib/zlib-1.2.8/contrib/minizip/mztools.c | 291 ++ .../zlib/zlib-1.2.8/contrib/minizip/mztools.h | 37 + test/zlib/zlib-1.2.8/contrib/minizip/unzip.c | 2125 ++++++++++++ test/zlib/zlib-1.2.8/contrib/minizip/unzip.h | 437 +++ test/zlib/zlib-1.2.8/contrib/minizip/zip.c | 2007 +++++++++++ test/zlib/zlib-1.2.8/contrib/minizip/zip.h | 362 ++ .../zlib-1.2.8/contrib/pascal/example.pas | 599 ++++ .../zlib/zlib-1.2.8/contrib/pascal/readme.txt | 76 + .../zlib-1.2.8/contrib/pascal/zlibd32.mak | 99 + .../zlib-1.2.8/contrib/pascal/zlibpas.pas | 276 ++ test/zlib/zlib-1.2.8/contrib/puff/Makefile | 42 + test/zlib/zlib-1.2.8/contrib/puff/README | 63 + test/zlib/zlib-1.2.8/contrib/puff/puff.c | 840 +++++ test/zlib/zlib-1.2.8/contrib/puff/puff.h | 35 + test/zlib/zlib-1.2.8/contrib/puff/pufftest.c | 165 + test/zlib/zlib-1.2.8/contrib/puff/zeros.raw | Bin 0 -> 2517 bytes .../zlib-1.2.8/contrib/testzlib/testzlib.c | 275 ++ .../zlib-1.2.8/contrib/testzlib/testzlib.txt | 10 + test/zlib/zlib-1.2.8/contrib/untgz/Makefile | 14 + .../zlib-1.2.8/contrib/untgz/Makefile.msc | 17 + test/zlib/zlib-1.2.8/contrib/untgz/untgz.c | 674 ++++ .../zlib-1.2.8/contrib/vstudio/readme.txt | 65 + .../contrib/vstudio/vc10/miniunz.vcxproj | 310 ++ .../vstudio/vc10/miniunz.vcxproj.filters | 22 + .../contrib/vstudio/vc10/minizip.vcxproj | 307 ++ .../vstudio/vc10/minizip.vcxproj.filters | 22 + .../contrib/vstudio/vc10/testzlib.vcxproj | 420 +++ .../vstudio/vc10/testzlib.vcxproj.filters | 58 + .../contrib/vstudio/vc10/testzlibdll.vcxproj | 310 ++ .../vstudio/vc10/testzlibdll.vcxproj.filters | 22 + .../zlib-1.2.8/contrib/vstudio/vc10/zlib.rc | 32 + .../contrib/vstudio/vc10/zlibstat.vcxproj | 473 +++ .../vstudio/vc10/zlibstat.vcxproj.filters | 77 + .../contrib/vstudio/vc10/zlibvc.def | 143 + .../contrib/vstudio/vc10/zlibvc.sln | 135 + .../contrib/vstudio/vc10/zlibvc.vcxproj | 657 ++++ .../vstudio/vc10/zlibvc.vcxproj.filters | 118 + .../contrib/vstudio/vc11/miniunz.vcxproj | 314 ++ .../contrib/vstudio/vc11/minizip.vcxproj | 311 ++ .../contrib/vstudio/vc11/testzlib.vcxproj | 426 +++ .../contrib/vstudio/vc11/testzlibdll.vcxproj | 314 ++ .../zlib-1.2.8/contrib/vstudio/vc11/zlib.rc | 32 + .../contrib/vstudio/vc11/zlibstat.vcxproj | 464 +++ .../contrib/vstudio/vc11/zlibvc.def | 143 + .../contrib/vstudio/vc11/zlibvc.sln | 117 + .../contrib/vstudio/vc11/zlibvc.vcxproj | 688 ++++ .../contrib/vstudio/vc9/miniunz.vcproj | 565 ++++ .../contrib/vstudio/vc9/minizip.vcproj | 562 ++++ .../contrib/vstudio/vc9/testzlib.vcproj | 852 +++++ .../contrib/vstudio/vc9/testzlibdll.vcproj | 565 ++++ .../zlib-1.2.8/contrib/vstudio/vc9/zlib.rc | 32 + .../contrib/vstudio/vc9/zlibstat.vcproj | 835 +++++ .../zlib-1.2.8/contrib/vstudio/vc9/zlibvc.def | 143 + .../zlib-1.2.8/contrib/vstudio/vc9/zlibvc.sln | 144 + .../contrib/vstudio/vc9/zlibvc.vcproj | 1156 +++++++ test/zlib/zlib-1.2.8/crc32.c | 425 +++ test/zlib/zlib-1.2.8/crc32.h | 441 +++ test/zlib/zlib-1.2.8/deflate.c | 1967 +++++++++++ test/zlib/zlib-1.2.8/deflate.h | 346 ++ test/zlib/zlib-1.2.8/doc/algorithm.txt | 209 ++ test/zlib/zlib-1.2.8/doc/rfc1950.txt | 619 ++++ test/zlib/zlib-1.2.8/doc/rfc1951.txt | 955 ++++++ test/zlib/zlib-1.2.8/doc/rfc1952.txt | 675 ++++ test/zlib/zlib-1.2.8/doc/txtvsbin.txt | 107 + test/zlib/zlib-1.2.8/examples/README.examples | 49 + test/zlib/zlib-1.2.8/examples/enough.c | 572 ++++ test/zlib/zlib-1.2.8/examples/fitblk.c | 233 ++ test/zlib/zlib-1.2.8/examples/gun.c | 702 ++++ test/zlib/zlib-1.2.8/examples/gzappend.c | 504 +++ test/zlib/zlib-1.2.8/examples/gzjoin.c | 449 +++ test/zlib/zlib-1.2.8/examples/gzlog.c | 1059 ++++++ test/zlib/zlib-1.2.8/examples/gzlog.h | 91 + test/zlib/zlib-1.2.8/examples/zlib_how.html | 545 +++ test/zlib/zlib-1.2.8/examples/zpipe.c | 205 ++ test/zlib/zlib-1.2.8/examples/zran.c | 409 +++ test/zlib/zlib-1.2.8/gzclose.c | 25 + test/zlib/zlib-1.2.8/gzguts.h | 209 ++ test/zlib/zlib-1.2.8/gzlib.c | 634 ++++ test/zlib/zlib-1.2.8/gzread.c | 594 ++++ test/zlib/zlib-1.2.8/gzwrite.c | 577 ++++ test/zlib/zlib-1.2.8/infback.c | 640 ++++ test/zlib/zlib-1.2.8/inffast.c | 340 ++ test/zlib/zlib-1.2.8/inffast.h | 11 + test/zlib/zlib-1.2.8/inffixed.h | 94 + test/zlib/zlib-1.2.8/inflate.c | 1512 +++++++++ test/zlib/zlib-1.2.8/inflate.h | 122 + test/zlib/zlib-1.2.8/inftrees.c | 306 ++ test/zlib/zlib-1.2.8/inftrees.h | 62 + test/zlib/zlib-1.2.8/make_vms.com | 867 +++++ test/zlib/zlib-1.2.8/msdos/Makefile.bor | 115 + test/zlib/zlib-1.2.8/msdos/Makefile.dj2 | 104 + test/zlib/zlib-1.2.8/msdos/Makefile.emx | 69 + test/zlib/zlib-1.2.8/msdos/Makefile.msc | 112 + test/zlib/zlib-1.2.8/msdos/Makefile.tc | 100 + test/zlib/zlib-1.2.8/nintendods/Makefile | 126 + test/zlib/zlib-1.2.8/nintendods/README | 5 + test/zlib/zlib-1.2.8/old/Makefile.emx | 69 + test/zlib/zlib-1.2.8/old/Makefile.riscos | 151 + test/zlib/zlib-1.2.8/old/README | 3 + test/zlib/zlib-1.2.8/old/descrip.mms | 48 + test/zlib/zlib-1.2.8/old/os2/Makefile.os2 | 136 + test/zlib/zlib-1.2.8/old/os2/zlib.def | 51 + test/zlib/zlib-1.2.8/old/visual-basic.txt | 160 + test/zlib/zlib-1.2.8/qnx/package.qpg | 141 + test/zlib/zlib-1.2.8/test/example.c | 601 ++++ test/zlib/zlib-1.2.8/test/infcover.c | 671 ++++ test/zlib/zlib-1.2.8/test/minigzip.c | 651 ++++ test/zlib/zlib-1.2.8/treebuild.xml | 116 + test/zlib/zlib-1.2.8/trees.c | 1226 +++++++ test/zlib/zlib-1.2.8/trees.h | 128 + test/zlib/zlib-1.2.8/uncompr.c | 59 + test/zlib/zlib-1.2.8/watcom/watcom_f.mak | 43 + test/zlib/zlib-1.2.8/watcom/watcom_l.mak | 43 + test/zlib/zlib-1.2.8/win32/DLL_FAQ.txt | 397 +++ test/zlib/zlib-1.2.8/win32/Makefile.bor | 110 + test/zlib/zlib-1.2.8/win32/Makefile.gcc | 182 + test/zlib/zlib-1.2.8/win32/Makefile.msc | 163 + test/zlib/zlib-1.2.8/win32/README-WIN32.txt | 103 + test/zlib/zlib-1.2.8/win32/VisualC.txt | 3 + test/zlib/zlib-1.2.8/win32/zlib.def | 86 + test/zlib/zlib-1.2.8/win32/zlib1.rc | 40 + test/zlib/zlib-1.2.8/zconf.h | 511 +++ test/zlib/zlib-1.2.8/zconf.h.cmakein | 513 +++ test/zlib/zlib-1.2.8/zconf.h.in | 511 +++ test/zlib/zlib-1.2.8/zlib.3 | 151 + test/zlib/zlib-1.2.8/zlib.3.pdf | Bin 0 -> 8734 bytes test/zlib/zlib-1.2.8/zlib.h | 1768 ++++++++++ test/zlib/zlib-1.2.8/zlib.map | 83 + test/zlib/zlib-1.2.8/zlib.pc.cmakein | 13 + test/zlib/zlib-1.2.8/zlib.pc.in | 13 + test/zlib/zlib-1.2.8/zlib2ansi | 152 + test/zlib/zlib-1.2.8/zutil.c | 324 ++ test/zlib/zlib-1.2.8/zutil.h | 253 ++ test/zlib/ztest.hpp | 167 + 437 files changed, 87677 insertions(+), 7035 deletions(-) rename doc/{Jamfile => Jamfile.v2} (60%) create mode 100644 doc/examples.qbk create mode 100644 doc/images/CppCon2016.pdf create mode 100644 doc/images/CppCon2016.png mode change 100644 => 100755 doc/makeqbk.sh create mode 100644 doc/overview.qbk rename examples/{Jamfile => Jamfile.v2} (96%) create mode 100644 examples/ssl/CMakeLists.txt create mode 100644 examples/ssl/Jamfile.v2 create mode 100644 examples/ssl/http_ssl_example.cpp create mode 100644 examples/ssl/websocket_ssl_example.cpp rename {include => extras}/beast/doc_debug.hpp (100%) create mode 100644 include/beast/core/detail/clamp.hpp rename include/beast/core/{impl/prepare_buffers.ipp => detail/prepare_buffers.hpp} (52%) create mode 100644 include/beast/core/detail/sync_ostream.hpp create mode 100644 include/beast/core/detail/type_traits.hpp create mode 100644 include/beast/core/handler_helpers.hpp create mode 100644 include/beast/core/handler_ptr.hpp create mode 100644 include/beast/core/impl/handler_ptr.ipp create mode 100644 include/beast/core/prepare_buffer.hpp create mode 100644 include/beast/http/basic_fields.hpp delete mode 100644 include/beast/http/basic_headers.hpp delete mode 100644 include/beast/http/body_type.hpp create mode 100644 include/beast/http/chunk_encode.hpp create mode 100644 include/beast/http/detail/basic_fields.hpp delete mode 100644 include/beast/http/detail/has_content_length.hpp rename include/beast/http/{headers.hpp => fields.hpp} (62%) create mode 100644 include/beast/http/header_parser_v1.hpp rename include/beast/http/impl/{basic_headers.ipp => basic_fields.ipp} (70%) create mode 100644 include/beast/http/impl/message.ipp delete mode 100644 include/beast/http/impl/message_v1.ipp create mode 100644 include/beast/http/impl/parse.ipp create mode 100644 include/beast/http/impl/parse_error.ipp delete mode 100644 include/beast/http/message_v1.hpp create mode 100644 include/beast/http/parse.hpp delete mode 100644 include/beast/websocket/detail/error.hpp create mode 100644 include/beast/websocket/impl/accept.ipp delete mode 100644 include/beast/websocket/impl/accept_op.ipp rename include/beast/websocket/impl/{close_op.ipp => close.ipp} (63%) rename include/beast/websocket/impl/{handshake_op.ipp => handshake.ipp} (52%) rename include/beast/websocket/impl/{ping_op.ipp => ping.ipp} (54%) rename include/beast/websocket/impl/{read_frame_op.ipp => read.ipp} (56%) delete mode 100644 include/beast/websocket/impl/read_op.ipp delete mode 100644 include/beast/websocket/impl/response_op.ipp create mode 100644 include/beast/websocket/impl/write.ipp delete mode 100644 include/beast/websocket/impl/write_frame_op.ipp delete mode 100644 include/beast/websocket/impl/write_op.ipp create mode 100644 include/beast/zlib.hpp create mode 100644 include/beast/zlib/deflate_stream.hpp create mode 100644 include/beast/zlib/detail/bitstream.hpp create mode 100644 include/beast/zlib/detail/deflate_stream.hpp create mode 100644 include/beast/zlib/detail/inflate_stream.hpp create mode 100644 include/beast/zlib/detail/ranges.hpp create mode 100644 include/beast/zlib/detail/window.hpp create mode 100644 include/beast/zlib/error.hpp create mode 100644 include/beast/zlib/impl/error.ipp create mode 100644 include/beast/zlib/inflate_stream.hpp create mode 100644 include/beast/zlib/zlib.hpp create mode 100644 index.html create mode 100644 scripts/valgrind.supp rename test/{websocket/stream_base.cpp => core/clamp.cpp} (57%) create mode 100644 test/core/handler_ptr.cpp create mode 100644 test/core/zlib.cpp rename test/http/{basic_headers.cpp => basic_fields.cpp} (82%) rename test/http/{headers.cpp => fields.cpp} (89%) create mode 100644 test/http/header_parser_v1.cpp delete mode 100644 test/http/message_v1.cpp rename test/http/{body_type.cpp => parse.cpp} (88%) create mode 100644 test/zlib.cpp create mode 100644 test/zlib/CMakeLists.txt create mode 100644 test/zlib/deflate_stream.cpp create mode 100644 test/zlib/error.cpp create mode 100644 test/zlib/inflate_stream.cpp create mode 100644 test/zlib/zlib-1.2.8/CMakeLists.txt create mode 100644 test/zlib/zlib-1.2.8/ChangeLog create mode 100644 test/zlib/zlib-1.2.8/FAQ create mode 100644 test/zlib/zlib-1.2.8/INDEX create mode 100644 test/zlib/zlib-1.2.8/Makefile create mode 100644 test/zlib/zlib-1.2.8/Makefile.in create mode 100644 test/zlib/zlib-1.2.8/README create mode 100644 test/zlib/zlib-1.2.8/adler32.c create mode 100644 test/zlib/zlib-1.2.8/amiga/Makefile.pup create mode 100644 test/zlib/zlib-1.2.8/amiga/Makefile.sas create mode 100644 test/zlib/zlib-1.2.8/as400/bndsrc create mode 100644 test/zlib/zlib-1.2.8/as400/compile.clp create mode 100644 test/zlib/zlib-1.2.8/as400/readme.txt create mode 100644 test/zlib/zlib-1.2.8/as400/zlib.inc create mode 100644 test/zlib/zlib-1.2.8/compress.c create mode 100644 test/zlib/zlib-1.2.8/configure create mode 100644 test/zlib/zlib-1.2.8/contrib/README.contrib create mode 100644 test/zlib/zlib-1.2.8/contrib/ada/buffer_demo.adb create mode 100644 test/zlib/zlib-1.2.8/contrib/ada/mtest.adb create mode 100644 test/zlib/zlib-1.2.8/contrib/ada/read.adb create mode 100644 test/zlib/zlib-1.2.8/contrib/ada/readme.txt create mode 100644 test/zlib/zlib-1.2.8/contrib/ada/test.adb create mode 100644 test/zlib/zlib-1.2.8/contrib/ada/zlib-streams.adb create mode 100644 test/zlib/zlib-1.2.8/contrib/ada/zlib-streams.ads create mode 100644 test/zlib/zlib-1.2.8/contrib/ada/zlib-thin.adb create mode 100644 test/zlib/zlib-1.2.8/contrib/ada/zlib-thin.ads create mode 100644 test/zlib/zlib-1.2.8/contrib/ada/zlib.adb create mode 100644 test/zlib/zlib-1.2.8/contrib/ada/zlib.ads create mode 100644 test/zlib/zlib-1.2.8/contrib/ada/zlib.gpr create mode 100644 test/zlib/zlib-1.2.8/contrib/amd64/amd64-match.S create mode 100644 test/zlib/zlib-1.2.8/contrib/asm686/README.686 create mode 100644 test/zlib/zlib-1.2.8/contrib/asm686/match.S create mode 100644 test/zlib/zlib-1.2.8/contrib/blast/Makefile create mode 100644 test/zlib/zlib-1.2.8/contrib/blast/README create mode 100644 test/zlib/zlib-1.2.8/contrib/blast/blast.c create mode 100644 test/zlib/zlib-1.2.8/contrib/blast/blast.h create mode 100644 test/zlib/zlib-1.2.8/contrib/blast/test.pk create mode 100644 test/zlib/zlib-1.2.8/contrib/blast/test.txt create mode 100644 test/zlib/zlib-1.2.8/contrib/delphi/ZLib.pas create mode 100644 test/zlib/zlib-1.2.8/contrib/delphi/ZLibConst.pas create mode 100644 test/zlib/zlib-1.2.8/contrib/delphi/readme.txt create mode 100644 test/zlib/zlib-1.2.8/contrib/delphi/zlibd32.mak create mode 100644 test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib.build create mode 100644 test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib.chm create mode 100644 test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib.sln create mode 100644 test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/AssemblyInfo.cs create mode 100644 test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/ChecksumImpl.cs create mode 100644 test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/CircularBuffer.cs create mode 100644 test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/CodecBase.cs create mode 100644 test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/Deflater.cs create mode 100644 test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/DotZLib.cs create mode 100644 test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/DotZLib.csproj create mode 100644 test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/GZipStream.cs create mode 100644 test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/Inflater.cs create mode 100644 test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/UnitTests.cs create mode 100644 test/zlib/zlib-1.2.8/contrib/dotzlib/LICENSE_1_0.txt create mode 100644 test/zlib/zlib-1.2.8/contrib/dotzlib/readme.txt create mode 100644 test/zlib/zlib-1.2.8/contrib/gcc_gvmat64/gvmat64.S create mode 100644 test/zlib/zlib-1.2.8/contrib/infback9/README create mode 100644 test/zlib/zlib-1.2.8/contrib/infback9/infback9.c create mode 100644 test/zlib/zlib-1.2.8/contrib/infback9/infback9.h create mode 100644 test/zlib/zlib-1.2.8/contrib/infback9/inffix9.h create mode 100644 test/zlib/zlib-1.2.8/contrib/infback9/inflate9.h create mode 100644 test/zlib/zlib-1.2.8/contrib/infback9/inftree9.c create mode 100644 test/zlib/zlib-1.2.8/contrib/infback9/inftree9.h create mode 100644 test/zlib/zlib-1.2.8/contrib/inflate86/inffas86.c create mode 100644 test/zlib/zlib-1.2.8/contrib/inflate86/inffast.S create mode 100644 test/zlib/zlib-1.2.8/contrib/iostream/test.cpp create mode 100644 test/zlib/zlib-1.2.8/contrib/iostream/zfstream.cpp create mode 100644 test/zlib/zlib-1.2.8/contrib/iostream/zfstream.h create mode 100644 test/zlib/zlib-1.2.8/contrib/iostream2/zstream.h create mode 100644 test/zlib/zlib-1.2.8/contrib/iostream2/zstream_test.cpp create mode 100644 test/zlib/zlib-1.2.8/contrib/iostream3/README create mode 100644 test/zlib/zlib-1.2.8/contrib/iostream3/TODO create mode 100644 test/zlib/zlib-1.2.8/contrib/iostream3/test.cc create mode 100644 test/zlib/zlib-1.2.8/contrib/iostream3/zfstream.cc create mode 100644 test/zlib/zlib-1.2.8/contrib/iostream3/zfstream.h create mode 100644 test/zlib/zlib-1.2.8/contrib/masmx64/bld_ml64.bat create mode 100644 test/zlib/zlib-1.2.8/contrib/masmx64/gvmat64.asm create mode 100644 test/zlib/zlib-1.2.8/contrib/masmx64/inffas8664.c create mode 100644 test/zlib/zlib-1.2.8/contrib/masmx64/inffasx64.asm create mode 100644 test/zlib/zlib-1.2.8/contrib/masmx64/readme.txt create mode 100644 test/zlib/zlib-1.2.8/contrib/masmx86/bld_ml32.bat create mode 100644 test/zlib/zlib-1.2.8/contrib/masmx86/inffas32.asm create mode 100644 test/zlib/zlib-1.2.8/contrib/masmx86/match686.asm create mode 100644 test/zlib/zlib-1.2.8/contrib/masmx86/readme.txt create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/Makefile create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/Makefile.am create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/MiniZip64_Changes.txt create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/MiniZip64_info.txt create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/configure.ac create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/crypt.h create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/ioapi.c create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/ioapi.h create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/iowin32.c create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/iowin32.h create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/make_vms.com create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/miniunz.c create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/miniunzip.1 create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/minizip.1 create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/minizip.c create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/minizip.pc.in create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/mztools.c create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/mztools.h create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/unzip.c create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/unzip.h create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/zip.c create mode 100644 test/zlib/zlib-1.2.8/contrib/minizip/zip.h create mode 100644 test/zlib/zlib-1.2.8/contrib/pascal/example.pas create mode 100644 test/zlib/zlib-1.2.8/contrib/pascal/readme.txt create mode 100644 test/zlib/zlib-1.2.8/contrib/pascal/zlibd32.mak create mode 100644 test/zlib/zlib-1.2.8/contrib/pascal/zlibpas.pas create mode 100644 test/zlib/zlib-1.2.8/contrib/puff/Makefile create mode 100644 test/zlib/zlib-1.2.8/contrib/puff/README create mode 100644 test/zlib/zlib-1.2.8/contrib/puff/puff.c create mode 100644 test/zlib/zlib-1.2.8/contrib/puff/puff.h create mode 100644 test/zlib/zlib-1.2.8/contrib/puff/pufftest.c create mode 100644 test/zlib/zlib-1.2.8/contrib/puff/zeros.raw create mode 100644 test/zlib/zlib-1.2.8/contrib/testzlib/testzlib.c create mode 100644 test/zlib/zlib-1.2.8/contrib/testzlib/testzlib.txt create mode 100644 test/zlib/zlib-1.2.8/contrib/untgz/Makefile create mode 100644 test/zlib/zlib-1.2.8/contrib/untgz/Makefile.msc create mode 100644 test/zlib/zlib-1.2.8/contrib/untgz/untgz.c create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/readme.txt create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc10/miniunz.vcxproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc10/miniunz.vcxproj.filters create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc10/minizip.vcxproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc10/minizip.vcxproj.filters create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlib.vcxproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlib.vcxproj.filters create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlibdll.vcxproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlibdll.vcxproj.filters create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlib.rc create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibstat.vcxproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibstat.vcxproj.filters create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.def create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.sln create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.vcxproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.vcxproj.filters create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc11/miniunz.vcxproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc11/minizip.vcxproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc11/testzlib.vcxproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc11/testzlibdll.vcxproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlib.rc create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibstat.vcxproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibvc.def create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibvc.sln create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibvc.vcxproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc9/miniunz.vcproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc9/minizip.vcproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc9/testzlib.vcproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc9/testzlibdll.vcproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlib.rc create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibstat.vcproj create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibvc.def create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibvc.sln create mode 100644 test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibvc.vcproj create mode 100644 test/zlib/zlib-1.2.8/crc32.c create mode 100644 test/zlib/zlib-1.2.8/crc32.h create mode 100644 test/zlib/zlib-1.2.8/deflate.c create mode 100644 test/zlib/zlib-1.2.8/deflate.h create mode 100644 test/zlib/zlib-1.2.8/doc/algorithm.txt create mode 100644 test/zlib/zlib-1.2.8/doc/rfc1950.txt create mode 100644 test/zlib/zlib-1.2.8/doc/rfc1951.txt create mode 100644 test/zlib/zlib-1.2.8/doc/rfc1952.txt create mode 100644 test/zlib/zlib-1.2.8/doc/txtvsbin.txt create mode 100644 test/zlib/zlib-1.2.8/examples/README.examples create mode 100644 test/zlib/zlib-1.2.8/examples/enough.c create mode 100644 test/zlib/zlib-1.2.8/examples/fitblk.c create mode 100644 test/zlib/zlib-1.2.8/examples/gun.c create mode 100644 test/zlib/zlib-1.2.8/examples/gzappend.c create mode 100644 test/zlib/zlib-1.2.8/examples/gzjoin.c create mode 100644 test/zlib/zlib-1.2.8/examples/gzlog.c create mode 100644 test/zlib/zlib-1.2.8/examples/gzlog.h create mode 100644 test/zlib/zlib-1.2.8/examples/zlib_how.html create mode 100644 test/zlib/zlib-1.2.8/examples/zpipe.c create mode 100644 test/zlib/zlib-1.2.8/examples/zran.c create mode 100644 test/zlib/zlib-1.2.8/gzclose.c create mode 100644 test/zlib/zlib-1.2.8/gzguts.h create mode 100644 test/zlib/zlib-1.2.8/gzlib.c create mode 100644 test/zlib/zlib-1.2.8/gzread.c create mode 100644 test/zlib/zlib-1.2.8/gzwrite.c create mode 100644 test/zlib/zlib-1.2.8/infback.c create mode 100644 test/zlib/zlib-1.2.8/inffast.c create mode 100644 test/zlib/zlib-1.2.8/inffast.h create mode 100644 test/zlib/zlib-1.2.8/inffixed.h create mode 100644 test/zlib/zlib-1.2.8/inflate.c create mode 100644 test/zlib/zlib-1.2.8/inflate.h create mode 100644 test/zlib/zlib-1.2.8/inftrees.c create mode 100644 test/zlib/zlib-1.2.8/inftrees.h create mode 100644 test/zlib/zlib-1.2.8/make_vms.com create mode 100644 test/zlib/zlib-1.2.8/msdos/Makefile.bor create mode 100644 test/zlib/zlib-1.2.8/msdos/Makefile.dj2 create mode 100644 test/zlib/zlib-1.2.8/msdos/Makefile.emx create mode 100644 test/zlib/zlib-1.2.8/msdos/Makefile.msc create mode 100644 test/zlib/zlib-1.2.8/msdos/Makefile.tc create mode 100644 test/zlib/zlib-1.2.8/nintendods/Makefile create mode 100644 test/zlib/zlib-1.2.8/nintendods/README create mode 100644 test/zlib/zlib-1.2.8/old/Makefile.emx create mode 100644 test/zlib/zlib-1.2.8/old/Makefile.riscos create mode 100644 test/zlib/zlib-1.2.8/old/README create mode 100644 test/zlib/zlib-1.2.8/old/descrip.mms create mode 100644 test/zlib/zlib-1.2.8/old/os2/Makefile.os2 create mode 100644 test/zlib/zlib-1.2.8/old/os2/zlib.def create mode 100644 test/zlib/zlib-1.2.8/old/visual-basic.txt create mode 100644 test/zlib/zlib-1.2.8/qnx/package.qpg create mode 100644 test/zlib/zlib-1.2.8/test/example.c create mode 100644 test/zlib/zlib-1.2.8/test/infcover.c create mode 100644 test/zlib/zlib-1.2.8/test/minigzip.c create mode 100644 test/zlib/zlib-1.2.8/treebuild.xml create mode 100644 test/zlib/zlib-1.2.8/trees.c create mode 100644 test/zlib/zlib-1.2.8/trees.h create mode 100644 test/zlib/zlib-1.2.8/uncompr.c create mode 100644 test/zlib/zlib-1.2.8/watcom/watcom_f.mak create mode 100644 test/zlib/zlib-1.2.8/watcom/watcom_l.mak create mode 100644 test/zlib/zlib-1.2.8/win32/DLL_FAQ.txt create mode 100644 test/zlib/zlib-1.2.8/win32/Makefile.bor create mode 100644 test/zlib/zlib-1.2.8/win32/Makefile.gcc create mode 100644 test/zlib/zlib-1.2.8/win32/Makefile.msc create mode 100644 test/zlib/zlib-1.2.8/win32/README-WIN32.txt create mode 100644 test/zlib/zlib-1.2.8/win32/VisualC.txt create mode 100644 test/zlib/zlib-1.2.8/win32/zlib.def create mode 100644 test/zlib/zlib-1.2.8/win32/zlib1.rc create mode 100644 test/zlib/zlib-1.2.8/zconf.h create mode 100644 test/zlib/zlib-1.2.8/zconf.h.cmakein create mode 100644 test/zlib/zlib-1.2.8/zconf.h.in create mode 100644 test/zlib/zlib-1.2.8/zlib.3 create mode 100644 test/zlib/zlib-1.2.8/zlib.3.pdf create mode 100644 test/zlib/zlib-1.2.8/zlib.h create mode 100644 test/zlib/zlib-1.2.8/zlib.map create mode 100644 test/zlib/zlib-1.2.8/zlib.pc.cmakein create mode 100644 test/zlib/zlib-1.2.8/zlib.pc.in create mode 100644 test/zlib/zlib-1.2.8/zlib2ansi create mode 100644 test/zlib/zlib-1.2.8/zutil.c create mode 100644 test/zlib/zlib-1.2.8/zutil.h create mode 100644 test/zlib/ztest.hpp diff --git a/.travis.yml b/.travis.yml index 57c16c5dd..96efe8e73 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ env: # to boost's .tar.gz. - LCOV_ROOT=$HOME/lcov - VALGRIND_ROOT=$HOME/valgrind-install - - BOOST_ROOT=$HOME/boost_1_60_0 - - BOOST_URL='http://downloads.sourceforge.net/project/boost/boost/1.60.0/boost_1_60_0.tar.gz?r=https%3A%2F%2Fsourceforge.net%2Fprojects%2Fboost%2Ffiles%2Fboost%2F1.60.0%2Fboost_1_60_0.tar.gz&ts=1460417589&use_mirror=netix' + - BOOST_ROOT=$HOME/boost_1_61_0 + - BOOST_URL='http://downloads.sourceforge.net/project/boost/boost/1.61.0/boost_1_61_0.tar.gz?use_mirror=netix' packages: &gcc5_pkgs - gcc-5 - g++-5 diff --git a/CHANGELOG.md b/CHANGELOG.md index d82c196bc..0ac23dea1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,183 @@ +1.0.0-b22 + +* Fix broken Intellisense +* Implement the Asio deallocation-before-invocation guarantee +* Add handler helpers +* Avoid copies in handler_alloc +* Update README.md example programs +* Fix websocket stream read documentation +* Disable Boost.Coroutine deprecation warning +* Update documentation examples + +-------------------------------------------------------------------------------- + +1.0.0-b21 + +* Remove extraneous includes + +-------------------------------------------------------------------------------- + +1.0.0-b20 + +ZLib + +* Add ZLib module + +API Changes: + +* Rename HTTP identifiers + +-------------------------------------------------------------------------------- + +1.0.0-b19 + +* Boost library min/max guidance +* Improvements to code coverage +* Use boost::lexical_cast instead of std::to_string +* Fix prepare_buffers value_type +* Fix consuming_buffers value_type +* Better buffer_cat + +HTTP + +* Make chunk_encode public +* Add write, async_write, operator<< for message_headers +* Add read, async_read for message_headers +* Fix with_body example + +WebSocket + +* Optimize utf8 validation +* Optimize mask operations + +API Changes: + +* Refactor message and message_headers declarations +* prepared_buffers is private +* consume_buffers is removed + +-------------------------------------------------------------------------------- + +1.0.0-b18 + +* Increase optimization settings for MSVC builds + +HTTP + +* Check invariants in parse_op: +* Clean up message docs + +WebSocket + +* Write buffer option does not change capacity +* Close connection during async_read on close frame +* Add pong, async pong to stream + +Core + +* Meet DynamicBuffer requirements for static_streambuf +* Fix write_frame masking and auto-fragment handling + +Extras + +* unit_test::suite fixes: + - New overload of fail() specifies file and line + - BEAST_EXPECTS only evaluates the reason string on a failure +* Add zlib module + +-------------------------------------------------------------------------------- + +1.0.0-b17 + +* Change implicit to default value in example +* Tidy up some declarations +* Fix basic_streambuf::capacity +* Add basic_streambuf::alloc_size +* Parser callbacks may not throw +* Fix Reader concept doc typo +* Add is_Reader trait +* Tidy up basic_headers for documentation +* Tidy up documentation +* Add basic_parser_v1::reset +* Fix handling of body_what::pause in basic_parser_v1 +* Add headers_parser +* Engaged invokable is destructible +* Improve websocket example in README.md +* Refactor read_size_helper + +API Changes: + +* Added init() to Reader requirements +* Reader must be nothrow constructible +* Reader is now constructed right before reading the body + - The message passed on construction is filled in +* Rework HTTP concepts: + - Writer uses write instead of operator() + - Refactor traits to use void_t + - Remove is_ReadableBody, is_WritableBody + - Add has_reader, has_writer, is_Reader, is_Writer + - More friendly compile errors on failed concept checks +* basic_parser_v1 requires all callbacks present +* on_headers parser callback now returns void +* on_body_what is a new required parser callback returning body_what + +-------------------------------------------------------------------------------- + +1.0.0-b16 + +* Make value optional in param-list +* Frame processing routines are member functions +* Fix on_headers called twice from basic_parser_v1 +* Constrain parser_v1 constructor +* Improve first line serialization +* Add pause option to on_headers interface +* Refactor base_parser_v1 callback traits: +* Refine Parser concept +* Relax ForwardIterator requirements in FieldSequence +* Fix websocket failure testing +* Refine Writer concept and fix exemplar in documentation + +API Changes: + +* Rename mask_buffer_size to write_buffer_size +* Make auto_fragment a boolean option + +The message class hierarchy is refactored (breaking change): + +* One message class now models both HTTP/1 and HTTP/2 messages +* message_v1, request_v1, response_v1 removed +* New classes basic_request and basic_response model + messages without the body. + + Error resolution: Callers should use message, request, + and response instead of message_v1, request_v1, and + response_v1 respectively. + +-------------------------------------------------------------------------------- + +1.0.0-b15 + +* rfc7230 section 3.3.2 compliance +* Add HTTPS example +* Add Secure WebSocket example +* Fix message_v1 constructor +* Tidy up DynamicBuffer requirements +* Tidy up error types and headers +* Fix handling empty HTTP headers in parser_v1 + +-------------------------------------------------------------------------------- + +1.0.0-b14 + +* Add missing rebind to handler_alloc +* Fix error handling in http server examples +* Fix CMake scripts for MinGW +* Use BOOST_ASSERT +* Better WebSocket decorator +* Update and tidy documentation + +-------------------------------------------------------------------------------- + 1.0.0-b13 * dstream improvements diff --git a/CMakeLists.txt b/CMakeLists.txt index 20530bbb2..9f760999a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,21 +6,51 @@ project (Beast) set_property (GLOBAL PROPERTY USE_FOLDERS ON) -if (WIN32) - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /W4 /wd4100 /bigobj /D _WIN32_WINNT=0x0601 /D_SCL_SECURE_NO_WARNINGS=1 /D_CRT_SECURE_NO_WARNINGS=1") +if (MSVC) + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4244 /MP /W4 /wd4100 /bigobj /D _WIN32_WINNT=0x0601 /D _SCL_SECURE_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1") + set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") + set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /Ob2 /Oi /Ot /GL /MT") + set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Oi /Ot /MT") + set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") + set (CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") + + # for RelWithDebInfo builds, disable incremental linking + # since CMake sets it ON by default for that build type and it + # causes warnings + string (REPLACE "/INCREMENTAL" "/INCREMENTAL:NO" replacement_flags + ${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO}) + set (CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO ${replacement_flags}) + else() set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_MULTITHREADED ON) find_package(Boost REQUIRED COMPONENTS coroutine context thread filesystem program_options system) - include_directories(${Boost_INCLUDE_DIRS}) + include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) link_directories(${Boost_LIBRARY_DIR}) set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads) set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wpedantic") + "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra -Wpedantic -Wno-unused-parameter") +endif() + +add_definitions ("-DBOOST_COROUTINES_NO_DEPRECATION_WARNING") + +if (APPLE AND NOT DEFINED ENV{OPENSSL_ROOT_DIR}) + find_program(HOMEBREW brew) + if (NOT HOMEBREW STREQUAL "HOMEBREW-NOTFOUND") + execute_process(COMMAND brew --prefix openssl + OUTPUT_VARIABLE OPENSSL_ROOT_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() +endif() + +find_package(OpenSSL) + +if (MINGW) + link_libraries(${Boost_LIBRARIES} ws2_32 mswsock) endif() if ("${VARIANT}" STREQUAL "coverage") @@ -53,7 +83,6 @@ function(DoGroupSources curdir rootdir folder) source_group("" FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child}) else() string(REGEX REPLACE ^${rootdir} ${folder} groupname ${curdir}) - #set(groupname ${curdir}) string(REPLACE "/" "\\" groupname ${groupname}) source_group(${groupname} FILES ${PROJECT_SOURCE_DIR}/${curdir}/${child}) endif() @@ -78,7 +107,14 @@ file(GLOB_RECURSE EXTRAS_INCLUDES ) add_subdirectory (examples) +if (NOT OPENSSL_FOUND) + message("OpenSSL not found. Not building examples/ssl") +else() + add_subdirectory (examples/ssl) +endif() + add_subdirectory (test) add_subdirectory (test/core) add_subdirectory (test/http) add_subdirectory (test/websocket) +add_subdirectory (test/zlib) diff --git a/Jamroot b/Jamroot index 78951028d..1f8278535 100644 --- a/Jamroot +++ b/Jamroot @@ -37,7 +37,7 @@ else if [ os.name ] = HAIKU if [ os.name ] = NT { lib ssl : : ssleay32 ; - lib crypto : : libeay32 ; + lib crypto : : libeay32 ; } else { @@ -87,20 +87,20 @@ project beast /boost/coroutine//boost_coroutine /boost/filesystem//boost_filesystem /boost/program_options//boost_program_options -# ssl -# crypto BOOST_ALL_NO_LIB=1 - BOOST_SYSTEM_NO_DEPRECATED=1 multi - static shared on gcc:-std=c++11 - gcc:-Wno-unused-variable + gcc:-Wno-unused-parameter clang:-std=c++11 + clang:-Wno-unused-parameter + gcc:-Wno-unused-variable # Temporary until we can figure out -isystem + clang:-Wno-unused-variable # Temporary until we can figure out -isystem msvc:_SCL_SECURE_NO_WARNINGS=1 msvc:_CRT_SECURE_NO_WARNINGS=1 - msvc:-bigobj + msvc:"/wd4100 /bigobj" + msvc,release:"/Ob2 /Oi /Ot" LINUX:_XOPEN_SOURCE=600 LINUX:_GNU_SOURCE=1 SOLARIS:_XOPEN_SOURCE=500 @@ -113,12 +113,7 @@ project beast NT,gcc:ws2_32 NT,gcc:mswsock NT,gcc-cygwin:__USE_W32_SOCKETS - HPUX,gcc:_XOPEN_SOURCE_EXTENDED - HPUX:ipv6 - QNXNTO:socket - HAIKU:network : usage-requirements - . : build-dir bin ; diff --git a/README.md b/README.md index 70c0e0209..c2fdc0f60 100644 --- a/README.md +++ b/README.md @@ -12,16 +12,15 @@ --- -## CppCon 2016 +## Beast at CppCon 2016 -I will be giving a lightning talk on Beast at CppCon 2016 in Bellevue, -Washington from September 18 to September 22. If you'd like to meet me -and hear the talk or ask questions about Beast feel free to approach -me in person or send me an email at vinnie.falco@gmail.com to schedule -some time. +Presentation +(slides: CppCon2016.pdf) -About CppCon 2016: -http://cppcon.org + +Beast + --- @@ -96,7 +95,7 @@ using the `git subtree` or `git submodule` commands). Then, edit your build scripts to add the `include/` directory to the list of paths checked by the C++ compiler when searching for includes. Beast `#include` lines will look like this: -``` +```C++ #include #include ``` @@ -137,6 +136,7 @@ The files in the repository are laid out thusly: ./ bin/ Holds executables and project files bin64/ Holds 64-bit Windows executables and project files + doc/ Source code and scripts for the documentation include/ Add this to your compiler includes beast/ extras/ Additional APIs, may change @@ -171,14 +171,14 @@ int main() // WebSocket connect and send message using beast beast::websocket::stream ws{sock}; ws.handshake(host, "/"); - ws.write(boost::asio::buffer("Hello, world!")); + ws.write(boost::asio::buffer(std::string("Hello, world!"))); // Receive WebSocket message, print and close using beast beast::streambuf sb; beast::websocket::opcode op; ws.read(op, sb); ws.close(beast::websocket::close_code::normal); - std::cout << to_string(sb.data()) << "\n"; + std::cout << beast::to_string(sb.data()) << "\n"; } ``` @@ -186,6 +186,7 @@ Example HTTP program: ```C++ #include #include +#include #include #include @@ -200,18 +201,19 @@ int main() r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"})); // Send HTTP request using beast - beast::http::request_v1 req; + beast::http::request req; req.method = "GET"; req.url = "/"; req.version = 11; - req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port())); - req.headers.replace("User-Agent", "Beast"); + req.fields.replace("Host", host + ":" + + boost::lexical_cast(sock.remote_endpoint().port())); + req.fields.replace("User-Agent", "Beast"); beast::http::prepare(req); beast::http::write(sock, req); // Receive and print HTTP response using beast beast::streambuf sb; - beast::http::response_v1 resp; + beast::http::response resp; beast::http::read(sock, sb, resp); std::cout << resp; } diff --git a/TODO.txt b/TODO.txt index 0282538b2..13de4b341 100644 --- a/TODO.txt +++ b/TODO.txt @@ -18,6 +18,8 @@ Core: * Complete allocator testing in basic_streambuf WebSocket: +* Minimize sizeof(websocket::stream) +* Move check for message size limit to account for compression * more invokable unit test coverage * More control over the HTTP request and response during handshakes * optimized versions of key/masking, choose prepared_key size diff --git a/doc/Jamfile b/doc/Jamfile.v2 similarity index 60% rename from doc/Jamfile rename to doc/Jamfile.v2 index 35e113110..8e78d6cd8 100644 --- a/doc/Jamfile +++ b/doc/Jamfile.v2 @@ -15,15 +15,15 @@ using boostbook ; using quickbook ; using doxygen ; -xml beast_boostbook : master.qbk ; +import quickbook ; -path-constant out : . ; +path-constant here : . ; install stylesheets : $(broot)/doc/src/boostbook.css : - $(out)/html + $(here)/html ; explicit stylesheets ; @@ -35,7 +35,7 @@ install images images/body.png images/message.png : - $(out)/html/images + $(here)/html/images ; explicit images ; @@ -44,40 +44,54 @@ install callouts : [ glob $(broot)/doc/src/images/callouts/*.png ] : - $(out)/html/images/callouts + $(here)/html/images/callouts ; explicit callout ; -boostbook doc +install examples : - beast_boostbook + [ glob + ../examples/*.cpp + ../examples/*.hpp + ../examples/ssl/*.cpp + ../examples/ssl/*.hpp + ] : - chapter.autolabel=0 - boost.image.src=images/beast.png - boost.image.alt="Beast Logo" - boost.image.w=2400 - boost.image.h=80 - boost.root=$(broot) - chapter.autolabel=0 - chunk.first.sections=1 # Chunk the first top-level section? - chunk.section.depth=8 # Depth to which sections should be chunked - generate.section.toc.level=1 # Control depth of TOC generation in sections - toc.max.depth=2 # How many levels should be created for each TOC? - toc.section.depth=2 # How deep should recursive sections appear in the TOC? - : - temp - stylesheets - images + $(here)/html/examples ; -#explicit doc ; -# nav.layout=none -# html:location=../bin/doc/html -# generate.toc="chapter nop section nop" -# root.filename=index -# output-root="../bin/html" +explicit examples ; +xml doc + : + master.qbk + : + temp + $(broot)/tools/boostbook/dtd + ; + +boostbook boostdoc + : + doc + : + boost.root=$(broot) + boost.image.src=images/beast.png + boost.image.alt="Beast Logo" + boost.image.w=1330 + boost.image.h=80 + chapter.autolabel=0 + chunk.section.depth=8 # Depth to which sections should be chunked + chunk.first.sections=1 # Chunk the first top-level section? + toc.section.depth=8 # How deep should recursive sections appear in the TOC? + toc.max.depth=8 # How many levels should be created for each TOC? + generate.section.toc.level=8 # Control depth of TOC generation in sections + generate.toc="chapter nop section nop" + $(broot)/tools/boostbook/dtd + : + temp + examples + images + stylesheets + ; -#[include reference.qbk] -#[xinclude index.xml] diff --git a/doc/design.qbk b/doc/design.qbk index b65620905..55f62cead 100644 --- a/doc/design.qbk +++ b/doc/design.qbk @@ -5,44 +5,52 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:design Design choices] +[section:design Design Choices] + +[block ''' + + HTTP FAQ + WebSocket FAQ + Comparison to Zaphoyd Studios WebSocket++ + +'''] The implementations are driven by business needs of cryptocurrency server applications (e.g. [@https://ripple.com Ripple]) written in C++. These needs were not met by existing solutions so Beast was written from scratch -as a solution. Beast's design philosophy avoid flaws exhibited by other +as a solution. Beast's design philosophy avoids flaws exhibited by other libraries: +* Don't try to do too much. + * Don't sacrifice performance. -* Don't do too much, otherwise interfaces become rigid. +* Mimic Boost.Asio; familiarity breeds confidence. -* Symmetric interfaces (client and server the same, or close to it). +* Role-symmetric interfaces; client and server the same (or close to it). -* Emulate Boost.Asio interfaces as much as possible, since Asio is - proven and it is familiar to users. +* Leave important decisions to the user, such as allocating memory or + managing flow control. -* Let library users make the important decisions such as how to - allocate memory or how to leverage flow control. - -Beast uses the [link beast.types.DynamicBuffer [*`DynamicBuffer`]] concept -presented in the Netwoking TS, and relies heavily on the Boost.Asio -[*`ConstBufferSequence`] and [*`MutableBufferSequence`] concepts for passing -buffers to functions. The authors have found the dynamic buffer and buffer -sequence interfaces to be optimal for interacting with Asio, and for other -tasks such as incremental parsing of data in buffers (for example, parsing -websocket frames stored in a [link beast.ref.static_streambuf `static_streambuf`]). +Beast uses the __DynamicBuffer__ concept presented in the Networking TS +(__N4588__), and relies heavily on the Boost.Asio __ConstBufferSequence__ +and __MutableBufferSequence__ concepts for passing buffers to functions. +The authors have found the dynamic buffer and buffer sequence interfaces to +be optimal for interacting with Asio, and for other tasks such as incremental +parsing of data in buffers (for example, parsing websocket frames stored +in a [link beast.ref.static_streambuf `static_streambuf`]). During the development of Beast the authors have studied other software packages and in particular the comments left during the Boost Review process -of other packages offering similar functionality. In this section we attempt -to address those issues. +of other packages offering similar functionality. In this section and the +FAQs that follow we attempt to answer those questions that are also applicable +to Beast. [variablelist [[ "I would also like to see instances of this library being used in production. That would give some evidence that the design - works in practice."" + works in practice." ][ Beast.HTTP and Beast.WebSocket are production ready and currently running on public servers receiving traffic and handling millions of @@ -56,25 +64,26 @@ to address those issues. ] -[section:http HTTP] -For HTTP we to model the message to maximize flexibility of implementation +[section:http HTTP FAQ] + +For HTTP we model the message to maximize flexibility of implementation strategies while allowing familiar verbs such as [*`read`] and [*`write`]. The HTTP interface is further driven by the needs of the WebSocket module, as a WebSocket session requires a HTTP Upgrade handshake exchange at the start. Other design goals: -* Don't try to invent a complete web server or client +* Keep it simple. -* Have simple free functions to send and receive messages. +* Stay low level; don't invent a whole web server or client. -* Allow the message object to be customized, +* Allow for customizations, if the user needs it. [variablelist [[ "Some more advanced examples, e.g. including TLS with client/server - certificates would help."" + certificates would help." ][ The HTTP interface doesn't try to reinvent the wheel, it just uses the `boost::asio::ip::tcp::socket` or `boost::asio::ssl::stream` that @@ -94,7 +103,7 @@ start. Other design goals: ]] [[ - "Cookies? Forms/File Uploads?"" + "Cookies? Forms/File Uploads?" ][ Cookies, or managing these types of HTTP headers in general, is the responsibility of higher levels. Beast.HTTP just tries to get complete @@ -107,7 +116,7 @@ start. Other design goals: [[ "...supporting TLS (is this a feature? If not this would be a show-stopper), - etc. + etc." ][ Beast.HTTP does not provide direct facilities for implementing TLS connections; however, the interfaces already existing on the @@ -126,17 +135,24 @@ start. Other design goals: over Asio. Such an implementation should serve as a building block upon which higher abstractions such as the aforementioned HTTP service or cgi-gateway can be built. + + One of the example programs implements a simple HTTP server that + delivers files from the filesystem. ]] [[ "You should send a 100-continue to ask for the rest of the body if required." ][ - These behaviors are best left to the calling software. A future library - can build on Beast.HTTP to provide these behaviors. + The Beast interface needs to support this functionality (by allowing this + special case of partial message parsing and serialization). Specifically, + it should let callers read the request up to just before the body, + and let callers write the request up to just before the body. However, + making use of this behavior should be up to callers (since Beast is low + level). ]] [[ - "What about HTTP/2?"" + "What about HTTP/2?" ][ Many reviewers feel that HTTP/2 support is an essential feature of a HTTP library. The authors agree that HTTP/2 is important but also @@ -145,13 +161,13 @@ start. Other design goals: and 1.1. The Beast.HTTP message model is suitable for HTTP/2 and can be re-used. - The IEFT HTTP Working Group adopted message compatiblity with HTTP/1.x + The IETF HTTP Working Group adopted message compatiblity with HTTP/1.x as an explicit goal. A parser can simply emit full headers after - decoding the compressed HTTP/2 headers. The stream ID is not logicaly + decoding the compressed HTTP/2 headers. The stream ID is not logically part of the message but rather message metadata and should be communicated out-of-band (see below). HTTP/2 sessions begin with a traditional HTTP/1.1 Upgrade similar in fashion to the WebSocket - upgrade. A HTTP/2 implementation can use existing Beast.HTTP primitives + upgrade. An HTTP/2 implementation can use existing Beast.HTTP primitives to perform this handshake. Free functions for HTTP/2 sessions are not possible because of the @@ -167,10 +183,55 @@ start. Other design goals: ] +[endsect] + + + +[section:websocket WebSocket FAQ] + +[variablelist + +[[ + What about message compression? +][ + The author is currently porting ZLib 1.2.8 to modern, header-only C++11 + that does not use macros or try to support ancient architectures. This + deflate implementation will be available as its own individually + usable interface, and also will be used to power Beast WebSocket's + permessage-deflate implementation, due Q1 of 2017. + + However, Beast currently has sufficient functionality that users can + begin taking advantage of the WebSocket protocol using this library + immediately. +]] + +[[ + Where is the TLS/SSL interface? +][ + The `websocket::stream` wraps the socket or stream that you provide + (for example, a `boost::asio::ip::tcp::socket` or a + `boost::asio::ssl::stream`). You establish your TLS connection using the + interface on `ssl::stream` like shown in all of the Asio examples, then + construct your `websocket::stream` around it. It works perfectly fine; + Beast.WebSocket doesn't try to reinvent the wheel or put a fresh coat of + interface paint on the `ssl::stream`. + + The WebSocket implementation [*does] provide support for shutting down + the TLS connection through the use of the ADL compile-time virtual functions + [link beast.ref.websocket__teardown `teardown`] and + [link beast.ref.websocket__async_teardown `async_teardown`]. These will + properly close the connection as per rfc6455 and overloads are available + for TLS streams. Callers may provide their own overloads of these functions + for user-defined next layer types. +]] + +] [endsect] -[section:websocket WebSocket] + + +[section:websocketpp Comparison to Zaphoyd Studios WebSocket++] [variablelist @@ -208,21 +269,19 @@ start. Other design goals: To get an idea of the complexity involved with implementing a transport, compare the asio transport to the [@https://github.com/zaphoyd/websocketpp/blob/378437aecdcb1dfe62096ffd5d944bf1f640ccc3/websocketpp/transport/iostream/connection.hpp#L59 `iostream` transport] - (a layer that allows websocket communication over a std iostream). + (a layer that allows websocket communication over a `std::iostream`). In contrast, Beast abstracts the transport by defining just one [*`NextLayer`] template argument The type requirements for [*`NextLayer`] are already familiar to users as they are documented in Asio: - [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html SyncReadStream], - [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html SyncWriteStream], - [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html AsyncReadStream], and - [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html AsyncWriteStream]. + __AsyncReadStream__, __AsyncWriteStream__, __SyncReadStream__, __SyncWriteStream__. + The type requirements for instantiating `beast::websocket::stream` versus `websocketpp::connection` with user defined types are vastly reduced (18 functions versus 2). Note that websocketpp connections are passed by `shared_ptr`. Beast does not use `shared_ptr` anywhere in its public interface. A `beast::websocket::stream` is constructible and movable in a manner identical - `to a boost::asio::ip::tcp::socket`. Callers can put such objects in a + to a `boost::asio::ip::tcp::socket`. Callers can put such objects in a `shared_ptr` if they want to, but there is no requirement to do so. [table @@ -283,8 +342,7 @@ start. Other design goals: implementation. Instead, it follows the Asio pattern. Calls to asynchronous initiation functions use the same method to invoke intermediate handlers as the method used to invoke the final handler, - through the - [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/asio_handler_invoke.html asio_handler_invoke] mechanism. + through the __asio_handler_invoke__ mechanism. The only requirement in Beast is that calls to asynchronous initiation functions are made from the same implicit or explicit strand. For @@ -314,7 +372,7 @@ start. Other design goals: websocketpp requires a one-time call to set the handler for each event in its interface (for example, upon message receipt). The handler is - represented by a `std::function equivalent`. Its important to recognize + represented by a `std::function` equivalent. Its important to recognize that the websocketpp interface performs type-erasure on this handler. In comparison, Beast handlers are specified in a manner identical to @@ -378,29 +436,27 @@ start. Other design goals: websocketpp defines a message buffer, passed in arguments by `shared_ptr`, and an associated message manager which permits - aggregation and memory reuse of memory. The implementation of + aggregation and reuse of memory. The implementation of `websocketpp::message` uses a `std::string` to hold the payload. If an incoming message is broken up into multiple frames, the string may be - reallocated for each continuation frame. The std::string always uses + reallocated for each continuation frame. The `std::string` always uses the standard allocator, it is not possible to customize the choice of allocator. Beast allows callers to specify the object for receiving the message or frame data, which is of any type meeting the requirements of - [@http://vinniefalco.github.io/beast/beast/types/DynamicBuffer.html [*DynamicBuffer]] - (modeled after `boost::asio::streambuf`). + __DynamicBuffer__ (modeled after `boost::asio::streambuf`). - Beast comes with the class `beast::basic_streambuf`, an efficient - implementation of the [*DynamicBuffer] concept which makes use of multiple + Beast comes with the class __basic_streambuf__, an efficient + implementation of the __DynamicBuffer__ concept which makes use of multiple allocated octet arrays. If an incoming message is broken up into multiple pieces, no reallocation occurs. Instead, new allocations are appended to the sequence when existing allocations are filled. Beast does not impose any particular memory management model on callers. The - `basic_streambuf` provided by beast supports standard allocators through - a template argument. Use the [*DynamicBuffer] that comes with beast, + __basic_streambuf__ provided by beast supports standard allocators through + a template argument. Use the __DynamicBuffer__ that comes with beast, customize the allocator if you desire, or provide your own type that - meets the - [@https://github.com/vinniefalco/Beast/blob/6c8b4b2f8dde72b01507e4ac7fde4ffea57ebc99/include/beast/basic_streambuf.hpp#L21 concept requirements]. + meets the requirements. [table [ @@ -596,44 +652,8 @@ start. Other design goals: ] ]] -[[ - What about message compression? -][ - The author is currently porting ZLib 1.2.8 to modern, header-only C++11 - that does not use macros or try to support ancient architectures. This - deflate implementation will be available as its own individually - usable interface, and also will be used to power Beast WebSocket's - permessage-deflate implementation, due Q4 of 2016. - - However, Beast currently has sufficient functionality that users can - begin taking advantage of the WebSocket protocol using this library - immediately. -]] - -[[ - Where is the TLS/SSL interface? -][ - The `websocket::stream` wraps the socket or stream that you provide - (for example, a `boost::asio::ip::tcp::socket` or a - `boost::asio::ssl::stream`). You establish your TLS connection using the - interface on `ssl::stream` like shown in all of the Asio examples, they - construct your `websocket::stream` around it. It works perfectly fine; - Beast.WebSocket doesn't try to reinvent the wheel or put a fresh coat of - interface paint on the `ssl::stream`. - - The WebSocket implementation [*does] provides support for shutting down - the TLS connection through the use of the ADL compile-time virtual functions - [link beast.ref.websocket__teardown `teardown`] and - [link beast.ref.websocket__async_teardown `async_teardown`]. These will - properly close the connection as per rfc6455 and overloads are available - for TLS streams. Callers may provide their own overloads of these functions - for user-defined next layer types. -]] - ] [endsect] - - [endsect] diff --git a/doc/examples.qbk b/doc/examples.qbk new file mode 100644 index 000000000..fd8695367 --- /dev/null +++ b/doc/examples.qbk @@ -0,0 +1,127 @@ +[/ + Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +] + +[section:example Examples] + +These usage examples are intended to quickly impress upon readers the +flavor of the library. They are complete programs which may be built +and run. Source code and build scripts for these programs may be found +in the examples directory. + +[heading HTTP GET] + +Use HTTP to request the root page from a website and print the response: + +``` +#include +#include +#include +#include +#include + +int main() +{ + // Normal boost::asio setup + std::string const host = "boost.org"; + boost::asio::io_service ios; + boost::asio::ip::tcp::resolver r{ios}; + boost::asio::ip::tcp::socket sock{ios}; + boost::asio::connect(sock, + r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"})); + + // Send HTTP request using beast + beast::http::request req; + req.method = "GET"; + req.url = "/"; + req.version = 11; + req.fields.replace("Host", host + ":" + + boost::lexical_cast(sock.remote_endpoint().port())); + req.fields.replace("User-Agent", "Beast"); + beast::http::prepare(req); + beast::http::write(sock, req); + + // Receive and print HTTP response using beast + beast::streambuf sb; + beast::http::response resp; + beast::http::read(sock, sb, resp); + std::cout << resp; +} +``` +[heading WebSocket] + +Establish a WebSocket connection, send a message and receive the reply: +``` +#include +#include +#include +#include +#include + +int main() +{ + // Normal boost::asio setup + std::string const host = "echo.websocket.org"; + boost::asio::io_service ios; + boost::asio::ip::tcp::resolver r{ios}; + boost::asio::ip::tcp::socket sock{ios}; + boost::asio::connect(sock, + r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"})); + + // WebSocket connect and send message using beast + beast::websocket::stream ws{sock}; + ws.handshake(host, "/"); + ws.write(boost::asio::buffer(std::string("Hello, world!"))); + + // Receive WebSocket message, print and close using beast + beast::streambuf sb; + beast::websocket::opcode op; + ws.read(op, sb); + ws.close(beast::websocket::close_code::normal); + std::cout << beast::to_string(sb.data()) << "\n"; +} +``` + +[heading Secure WebSocket] + +Establish a WebSocket connection over an encrypted TLS connection, +send a message and receive the reply. Requires OpenSSL to build. + +* [@examples/websocket_ssl_example.cpp] + +[heading HTTPS GET] + +This example demonstrates sending and receiving HTTP messages +over a TLS connection. Requires OpenSSL to build. + +* [@examples/http_ssl_example.cpp] + +[heading HTTP Crawl] + +This example retrieves the page at each of the most popular domains +as measured by Alexa. + +* [@examples/http_crawl.cpp] + +[heading HTTP Server] + +This example demonstrates both synchronous and asynchronous server +implementations. It also provides an example of implementing a [*Body] +type, in `file_body`. + +* [@examples/file_body.hpp] +* [@examples/http_async_server.hpp] +* [@examples/http_sync_server.hpp] +* [@examples/http_server.cpp] + +[heading Listings] + +These are stand-alone listings of the HTTP and WebSocket examples. + +* [@examples/http_example.cpp] +* [@examples/websocket_example.cpp] + +[endsect] diff --git a/doc/http.qbk b/doc/http.qbk index 81b89f484..8ef784ff4 100644 --- a/doc/http.qbk +++ b/doc/http.qbk @@ -5,138 +5,203 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:http HTTP] +[/ +ideas: + - complete send request walkthrough (client) + - complete receive response walkthrough (client) + - complete receive request walkthrough (server) + - complete send response walkthrough (server) -Beast.HTTP offers programmers simple and performant models of HTTP messages and + - Introduce concepts from simple to complex + - Smooth progression of new ideas building on the previous ideas + + - do we show a simplified message with collapsed fields? + - do we introduce `header` or `message` first? + + +contents: + Message (and header, fields) + Create request + Create response + Algorithms + Write + Read + Parse + Examples + Send Request + Receive Response + Receive Request + Send Response + Advanced + Responding to HEAD + Expect: 100-continue + Body (user defined) + + +section beast.http.examples Examples + +note + In the example code which follows, `socket` refers to an object of type + `boost::asio::ip::tcp::socket` which is currently connected to a remote peer. +] + + + +[section:http Using HTTP] + +[block ''' + + Message + Fields + Body + Algorithms + +'''] + +Beast offers programmers simple and performant models of HTTP messages and their associated operations including synchronous and asynchronous reading and -writing of messages in the HTTP/1 wire format using Boost.Asio. - -The HTTP protocol is described fully in -[@https://tools.ietf.org/html/rfc7230 rfc7230] - - - -[section:motivation Motivation] - -The HTTP protocol is pervasive in network applications. As C++ is a logical -choice for high performance network servers, there is great utility in solid -building blocks for manipulating, sending, and receiving HTTP messages -compliant with the Hypertext Transfer Protocol and the supplements that -follow. Unfortunately reliable implementations or industry standards do not -exist in C++. - -Beast.HTTP is built on Boost.Asio and uses its own robust header-only HTTP/1 -message parser modeled after the nodejs http-parser (written in C). A proposal -to add networking functionality to the C++ standard library, based on -Boost.Asio, is under consideration by the standards committee. Since the final -approved networking interface for the C++ standard library will likely closely -resemble the current interface of Boost.Asio, it is logical for Beast.HTTP to -use Boost.Asio as its network transport. - -[endsect] - - - -[section:scope Scope] - -This library is designed to be a building block for creating higher level -libraries. It is not designed to be end-user facing. There is no convenient -class that implements the core of a web server, nor is there a convenient -class to quickly perform common operations such as fetching a file or -connecting and retrieving a document from a secure connection. These -use-cases are important, but this library does not try to do that. Instead, -it offers primitives that can be used to build those user-facing algorithms. - -A HTTP message (referred to hereafter as "message") contains request or -response specific attributes, a series of zero or more name/value pairs -(collectively termed "headers"), and a series of octets called the message -body which may be zero in length. The HTTP protocol defines the client and -server roles: clients send messages called requests and servers send back -messages called responses. `http::message` models both requests and responses. -Beast aims to offer this functionality: - -* [*Model]: Provide a universal HTTP message class model. - -* [*Build]: Construct a new message and manipulate its contents. - -* [*Parse]: Deserialize a message from a network or memory stream in HTTP/1 wire format. - -* [*Serialize]: Serialize a message into a network or memory stream in HTTP/1 wire format. - -[note The documentation which follows assumes familiarity with -both Boost.Asio and the HTTP protocol specification described in -[@https://tools.ietf.org/html/rfc7230 rfc7230] ] - -[endsect] - - - -[section:usage Usage] +writing of messages and headers in the HTTP/1 wire format using Boost.Asio. [note - Sample code and identifiers mentioned in this section are written - as if the following declarations are in effect: + The following documentation assumes familiarity with both Boost.Asio + and the HTTP protocol specification described in __rfc7230__. Sample code + and identifiers mentioned in this section are written as if the following + declarations are in effect: ``` + #include #include using namespace beast; + using namespace beast::http; ``` ] -In the paragraphs that follow we describe the available interfaces for -performing typical operations such as interacting with a HTTP server -or handling simple requests. Subsequent sections cover the message model -and its customization points in more depth, for advanced applications. -[heading Declarations] -To do anything, a message must be declared. The message class template -requires at minimum, a value indicating whether the message is a request -(versus a response), and a `Body` type. The choice of `Body` determines the -kind of container used to represent the message body. Here we will -declare a HTTP/1 request that has a `std::string` for the body container: +[section:message Message] + +The HTTP protocol defines the client and server roles: clients send messages +called requests and servers send back messages called responses. A HTTP message +(referred to hereafter as "message") contains request or response specific +attributes (contained in the "Start Line"), a series of zero or more name/value +pairs (collectively termed "Fields"), and an optional series of octets called +the message body which may be zero in length. The start line for a HTTP request +includes a string called the method, a string called the URL, and a version +number indicating HTTP/1.0 or HTTP/1.1. For a response, the start line contains +an integer status code and a string called the reason phrase. Alternatively, a +HTTP message can be viewed as two parts: a header, followed by a body. + +[note + The Reason-Phrase is obsolete as of rfc7230. +] + +The __header__ class template models the header for HTTP/1 and HTTP/2 messages. +This class template is a family of specializations, one for requests and one +for responses, depending on the [*`isRequest`] template value. +The [*`Fields`] template type determines the type of associative container +used to store the field values. The provided __basic_fields__ class template +and __fields__ type alias are typical choices for the [*`Fields`] type, but +advanced applications may supply user defined types which meet the requirements. +The __message__ class template models the header and optional body for HTTP/1 +and HTTP/2 requests and responses. It is derived from the __header__ class +template with the same shared template parameters, and adds the `body` data +member. The message class template requires an additional template argument +type [*`Body`]. This type controls the container used to represent the body, +if any, as well as the algorithms needed to serialize and parse bodies of +that type. + +This illustration shows the declarations and members of the __header__ and +__message__ class templates, as well as the inheritance relationship: + +[$images/message.png [width 650px] [height 390px]] + +For notational convenience, these template type aliases are provided which +supply typical choices for the [*`Fields`] type: ``` - http::message_v1 req; +using request_header = header; +using response_header = header; + +template +using request = message; + +template +using response = message; ``` -Two type aliases are provided for notational convenience when declaring -HTTP/1 messages. These two statements declare a request and a response -respectively: -``` - http::request_v1 req; - http::response_v1 resp; -``` +The code examples below show how to create and fill in a request and response +object: -[heading Members] - -Message objects are default constructible, with public access to data members. -Request and response objects have some common members, and some members unique -to the message type. These statements set all the members in each message: -``` - http::request_v1 req; +[table Create Message +[[HTTP Request] [HTTP Response]] +[[ + ``` + request req; + req.version = 11; // HTTP/1.1 req.method = "GET"; - req.url = "/index.html"; - req.version = 11; // HTTP/1.1 - req.headers.insert("User-Agent", "hello_world"); - req.body = ""; + req.url = "/index.htm" + req.fields.insert("Accept", "text/html"); + req.fields.insert("Connection", "keep-alive"); + req.fields.insert("User-Agent", "Beast"); + ``` +][ + ``` + response res; + res.version = 11; // HTTP/1.1 + res.status = 200; + res.reason = "OK"; + res.fields.insert("Sever", "Beast"); + res.fields.insert("Content-Length", 4); + res.body = "****"; + ``` +]]] - http::response_v1 resp; - resp.status = 404; - resp.reason = "Not Found"; - resp.version = 10; // HTTP/1.0 - resp.headers.insert("Server", "Beast.HTTP"); - resp.body = "The requested resource was not found."; -``` +In the serialized format of a HTTP message, the header is represented as a +series of text lines ending in CRLF (`"\r\n"`). The end of the header is +indicated by a line containing only CRLF. Here are examples of serialized HTTP +request and response objects. The objects created above will produce these +results when serialized. Note that only the response has a body: -[heading Headers] +[table Serialized HTTP Request and Response +[[HTTP Request] [HTTP Response]] +[[ + ``` + GET /index.htm HTTP/1.1\r\n + Accept: text/html\r\n + Connection: keep-alive\r\n + User-Agent: Beast\r\n + \r\n + ``` +][ + ``` + 200 OK HTTP/1.1\r\n + Server: Beast\r\n + Content-Length: 4\r\n + \r\n + **** + ``` +]]] -The `message::headers` member is a container for setting the field/value -pairs in the message. These statements change the values of the headers -in the message passed: + + + +[endsect] + + + + +[section:fields Fields] + +The [*`Fields`] type represents a container that can set or retrieve the +fields in a message. Beast provides the +[link beast.ref.http__basic_fields `basic_fields`] class which serves +the needs for most users. It supports modification and inspection of values. +The field names are not case-sensitive. + +These statements change the values of the headers in the message passed: ``` template - void set_fields(http::request_v1& req) + void set_fields(request& req) { if(! req.exists("User-Agent")) req.insert("User-Agent", "myWebClient"); @@ -148,17 +213,24 @@ in the message passed: } ``` -[heading Body] +User defined [*`Fields`] types are possible. To support serialization, the +type must meet the requirements of __FieldSequence__. To support parsing using +the provided parser, the type must provide the `insert` member function. -The `message::body` member represents the message body. Depending on the -`Body` template argument type, this could be a writable container. The -following types, provided by the library, are suitable choices for the -`Body` type: +[endsect] + + + +[section:body Body] + +The message [*`Body`] template parameter controls both the type of the data +member of the resulting message object, and the algorithms used during parsing +and serialization. Beast provides three very common [*`Body`] types: * [link beast.ref.http__empty_body [*`empty_body`:]] An empty message body. Used in GET requests where there is no message body. Example: ``` - http::request_v1 req; + request req; req.version = 11; req.method = "GET"; req.url = "/index.html"; @@ -170,36 +242,77 @@ or response with simple text in the message body (such as an error message). Has the same insertion complexity of `std::string`. This is the type of body used in the examples: ``` - http::response_v1 resp; - static_assert(std::is_same::value); - resp.body = "Here is the data you requested"; + response res; + static_assert(std::is_same::value); + res.body = "Here is the data you requested"; ``` * [link beast.ref.http__streambuf_body [*`streambuf_body`:]] A body with a `value_type` of [link beast.ref.streambuf `streambuf`]: an efficient storage object which uses multiple octet arrays of varying lengths to represent data. -[heading Sockets] +[heading Advanced] -The library provides simple free functions modeled after Boost.Asio to -send and receive messages on TCP/IP sockets, SSL streams, or any object -which meets the Boost.Asio type requirements (SyncReadStream, SyncWriteStream, -AsyncReadStream, and AsyncWriteStream depending on the types of operations -performed). To send messages synchronously, use one of the `http:write` -functions: +User-defined types are possible for the message body, where the type meets the +[link beast.ref.Body [*`Body`]] requirements. This simplified class declaration +shows the customization points available to user-defined body types: + +[$images/body.png [width 510px] [height 210px]] + +* [*`value_type`]: Determines the type of the + [link beast.ref.http__message.body `message::body`] member. If this + type defines default construction, move, copy, or swap, then message objects + declared with this [*`Body`] will have those operations defined. + +* [*`reader`]: An optional nested type meeting the requirements of + [link beast.ref.Reader [*`Reader`]]. If present, this defines the algorithm + used for parsing bodies of this type. + +* [*`writer`]: An optional nested type meeting the requirements of + [link beast.ref.Writer [*`Writer`]]. If present, this defines the algorithm + used for serializing bodies of this type. + +The examples included with this library provide a Body implementation that +serializing message bodies that come from a file. + +[endsect] + + + +[section:algorithms Algorithms] + +Algorithms are provided to serialize and deserialize HTTP/1 messages on +streams. + +* [link beast.ref.http__read [*read]]: Deserialize a HTTP/1 __header__ or __message__ from a stream. +* [link beast.ref.http__write [*write]]: Serialize a HTTP/1 __header__ or __message__ to a stream. + +Asynchronous versions of these algorithms are also available: + +* [link beast.ref.http__async_read [*async_read]]: Deserialize a HTTP/1 __header__ or __message__ asynchronously from a stream. +* [link beast.ref.http__async_write [*async_write]]: Serialize a HTTP/1 __header__ or __message__ asynchronously to a stream. + +[heading Using Sockets] + +The free function algorithms are modeled after Boost.Asio to send and receive +messages on TCP/IP sockets, SSL streams, or any object which meets the +Boost.Asio type requirements (__SyncReadStream__, __SyncWriteStream__, +__AsyncReadStream__, and __AsyncWriteStream__ depending on the types of +operations performed). To send messages synchronously, use one of the +[link beast.ref.http__write `write`] functions: ``` void send_request(boost::asio::ip::tcp::socket& sock) { - http::request req; + request req; req.version = 11; req.method = "GET"; req.url = "/index.html"; ... - http::write(sock, req); // Throws exception on error + write(sock, req); // Throws exception on error ... // Alternatively boost::system::error:code ec; - http::write(sock, req, ec); + write(sock, req, ec); if(ec) std::cerr << "error writing http message: " << ec.message(); } @@ -209,27 +322,27 @@ An asynchronous interface is available: ``` void handle_write(boost::system::error_code); ... - http::request_v1 req; + request req; ... - http::async_write(sock, req, std::bind(&handle_write, std::placeholders::_1)); + async_write(sock, req, std::bind(&handle_write, std::placeholders::_1)); ``` When the implementation reads messages from a socket, it can read bytes lying after the end of the message if they are present (the alternative is to read a single byte at a time which is unsuitable for performance reasons). To store and re-use these extra bytes on subsequent messages, the read interface -requires an additional parameter: a [link beast.types.DynamicBuffer [*`DynamicBuffer`]] +requires an additional parameter: a [link beast.ref.DynamicBuffer [*`DynamicBuffer`]] object. This example reads a message from the socket, with the extra bytes stored in the streambuf parameter for use in a subsequent call to read: ``` boost::asio::streambuf sb; ... - http::response_v1 resp; - http::read(sock, sb, resp); // Throws exception on error + response res; + read(sock, sb, res); // Throws exception on error ... // Alternatively boost::system::error:code ec; - http::read(sock, sb, resp, ec); + read(sock, sb, res, ec); if(ec) std::cerr << "error reading http message: " << ec.message(); ``` @@ -241,116 +354,28 @@ called: void handle_read(boost::system::error_code); ... boost::asio::streambuf sb; - http::response_v1 resp; + response res; ... - http::async_read(sock, resp, std::bind(&handle_read, std::placeholders::_1)); + async_read(sock, res, std::bind(&handle_read, std::placeholders::_1)); ``` An alternative to using a `boost::asio::streambuf` is to use a -[link beast.ref.streambuf `beast::streambuf`], which meets the requirements of -[*`DynamicBuffer`] and is optimized for performance: +__streambuf__, which meets the requirements of __DynamicBuffer__ and +is optimized for performance: ``` void handle_read(boost::system::error_code); ... beast::streambuf sb; - http::response_v1 resp; - http::read(sock, sb, resp); + response res; + read(sock, sb, res); ``` The `read` implementation can use any object meeting the requirements of -[link beast.types.DynamicBuffer [*`DynamicBuffer`]], allowing callers to define custom +__DynamicBuffer__, allowing callers to define custom memory management strategies used by the implementation. [endsect] -[section:advanced Advanced] - -The spectrum of hardware and software platforms which perform these typical -HTTP operations is vast, ranging from powerful servers in large datacenters -to tiny resource-limited embedded devices. No single concrete implementation -of a class intended to model messages can efficiently serve all needs. -For example, an object that minimizes resources during parsing may not be -able to edit and change headers dynamically. A message that represents the -message body as a disk file may support sending but not parsing. Many efficient -and correct models of messages exist, supporting some or all of the -operations listed above. - -[heading Message model] - -The message class template and provided Body types are suitable for casual -library users. This section explains the message model for advanced users -who wish to take control over aspects of the implementation. We introduce -customization points for the header and body via class template arguments. -This illustration shows more detail about the -[link beast.ref.http__message [*`message`]] class template (boilerplate -present in the actual declaration has been removed for clarity): - -[$images/message.png [width 580px] [height 225px]] - -The default constructor, move special members, and copy special members are -all defaulted. A message is movable, copyable, or default constructible based -on the capabilities of its template arguments. - -Messages modeled in this fashion are ['complete], containing all of the -information required to perform the supported set of operations. They are -['first-class types], returnable from functions and composable. HTTP -requests and responses are distinct types, allowing functions to be -overloaded on the type of message. - [endsect] - - - -[section:headers Headers Type] - -The `Headers` type represents the field/value pairs present in every HTTP -message. These types implement the -[link beast.types.FieldSequence [*`FieldSequence`]] -concept. The value type of a field sequence is an object meeting the -requirements of [link beast.types.Field [*`Field`]]. The implementation can -serialize any instance of `Headers` that meets the field sequence requirements. -This example shows a function which returns `true` if the specified field -sequence has a connect field: -``` -template -bool -has_connect(FieldSequence const& fs) -{ - return std::find_if(fs.begin(), fs.end(), - [&](auto const& field) - { - return ci_equal(field.name(), "Connect"); - }); -} -``` - -[endsect] - - - -[section:body Body Type] - -The `Body` template argument in the `message` class must meet the -[link beast.types.Body [*`Body`] requirements]. It provides customization -of the data member in the message, the algorithm for parsing, and the -algorithm for serialization: - -[$images/body.png [width 510px] [height 210px]] - -Instances of the optional nested types `writer` and `reader` perform -serialization and deserialization of the message body. If either or -both of these types are present, the message becomes serializable, parsable, -or both. They model [link beast.types.Reader [*`Reader`]] and -[link beast.types.Writer [*`Writer`]] respectively. - -For specialized applications, users may implement their own types which -meet the requirements. The examples included with this library provide a -Body implementation used to serve files in a HTTP server. - -[endsect] - - -[endsect] - diff --git a/doc/images/CppCon2016.pdf b/doc/images/CppCon2016.pdf new file mode 100644 index 0000000000000000000000000000000000000000..464b63a0995823492de4bdc74cbfe1f6a685994e GIT binary patch literal 475799 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

%~&nVU66Rd90# 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 z

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

64P~jws{<^ZNFe6q1B6ce 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

D}wm+@Ug>BVnfMwOIvad2eRy* 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 z zzg#vFnz+w+kNu{}GdrD7-h$j5#YQ1sFk`mI(W?^iLX`tIyu(o1w$8HW7V9=YCXNac`7ee=j>kx>h1{OgvV_GrPhXCxlq1B zgI{&8Rdvh&trBJ>q=(QbdUWEQ(R{brhM|G-0ybqqx!Sz^2D@yZ!s;wuNNYQu8vLq5 zmsGpj{+X=foA9~W)ad5&x*^lhjcYwqLm20>qi2+HLyF@1wc$DI#D=KM>`C0#o3SzD zShyqf@#qj|XGy-w_66};Xnxm(NTQ1_ z1nkZlz0Xv2RMx}RvO-+Vc=$#r+hymxfn9=SJV}5E?1DUn#2;YOl(hqdI98E_zP;v9{TxM0T2QZ@5PBypg%WFWnh&DYV0n zaB}C7xtOJp@rWdhH@PpPiPDJ*@r5J#;2^eMDLw->0r@tg+ykY0X2+vl60akuXCn!3@3w%#1KcHH=}UbISU zy=VhZcc0m`wxgaSu_lq9KRnGtxu)6DzFYKqISm)s*@k+_TIp5+kr_A@SculQd(!vR za^QsjEPjo$HI1^}w%v@_M9}dXyKytUNj(up<1y!O6SzVH9!4PnMPq3Vr9+r&2>hKk zm=vuKWn#`?We{RD5lIDZ{L8ppI{Em4-S!6#^1~){bj&8-)ooU^RMJ|KXHr(1$5u`I zt>xa5#6)O<2{jj?W=1PFsp%AKl=`h(sDJ0d)3h&kbw7}P8Nk}lhs{aHmv!4~$4Ljw zKxru__X1E3&Ijy8#M+%8E3!jmF8xYY@{;YFZKvufI-IpVj9xc}?;Pa7xl&Ym2Sp}~ zwB*zktI*`V+I7xtj&1guSdcER1pZ)L<9rjkx|eI+IMMEs-*kPxGg``DLC@efG3>wNuv(sFYg9S zu(T~U(Q{j}<`hEPubXD+TG(0+o3h&QS{^I52@m3uW;VMbJfGt--^=tx?7oHQ5k~Mv z1E2tFJ}fi{=dyWG2>mhI{yPx*qv!smGyg(! z#qu9DSM*GD{~ZV^o!B5NA@jHxEp}T1waV$mj3XlWHo;BQ(zr$q0G^a{d9cuSY9 zIgyux#unO_Y=mGs#5D8{*De3rFU(l99Oj1th4%SP#@+~fiE@fRdr`9MjF=NR z1(#wF!yCDph!VoLQ1HU0S-&*oGy?TNE0(GVX`v9 zRqX@o$mB;TTCL%#$aVPHbHVzdePnal*{b<`yj@7SVr%=CZU#&I%NXeC6%TH+`#B3iDb@D7vLkN8D5 zuetSmj_7Ft|uO7!-})wpD&Se3nt!OqpiPQMeGbLOsWBEc(OL(Mogs^;UaG0H2QqTYH!+ZWi9a|*lxQZ*h&TO;Dtdi8Ds`^xJECzv5N(p-T0 zxjT%CSu$L|VAthk(T94-A3kme{XpcMU`lTAwMi?QtO(6892XEJAU`K@%qZZ+ZS@&@ z=D&VLZN`yBH?O8~b+~C%?s7p2z<>FYDJfkvfn;h*#cH+Zl6nLC5>*Z&#|!QjQ+lSU zWy{{MZbb!Ou_58w_kZYpa0n zYE8u~EodjJvdBVAUoG1bYL+RBubjPf5S|@t03wIQNtPUoL0*WE<}C)=|7_l}_`|&Q4jI)NEM#yb1xP%? z54)0B@CG1ET0B`KIg0<$k=tsO4fbomed7{q>h6I1ky4v(8Gt^^!xr3PbrKL)@7|Xw zl*8smYi@;_gpTjDsuClSTT;$~WPMPB;r#V-cN<)UM0*n8nf9hvge4lMA-+S`H@ex- zY6M%7@xXk#R*hHjc$TBab6qCj6=eMZSW{_jwPf*7SE?T{l@@45zClxmn#zCk-R)R7 zJnoHAbSNnHxH`8iv82uDMz+~KN0LnE)vW(4NVNPI$2>#65A0D(DYRJj&I5>Y-{$x) zN5TK4o$If9{V!KD^#3$(F?_1MS=bmqmE}x-xuW@>Caynv@LyIme_`Tc{f{Otx=$-E z>z{30bKl)`k(C-Aw9L0GREiEAYep&fcbrR1u(^WU=fHgtCRwOdoYm@As)Z* zp+j4T!-S8sZukFyBxePumq9>O?2|)q4etk+(F7gCW5^xlEpa_ic0oFoH?MjEb_S7*-qMgtOUQi8!b&{I%w~0L&?T6HNE6yrJHNw^VuO_J*Tso znl>6>s6^Uw#lhmKw;eiFyEsG56d+4l`!}8S=?#A4^H$Xz2(WL%6R#1fUOt7LD{hWm z#j&ZOA!efD>cs^&HogPDJDq!J;a>85xtkcmrlqx!egE9-1u6&zE(%=@9mDDEFlRfK z&R`%Si`H&>_uJt|Z)d4VwkOP)LgsbKs%S;Hcd!joO&~$;coPUy?haYdJyiZ-erX8L zJN7I&^43Y^yUu&|%VZqHFQlUqA&*n2ni0xBmkc@B zOwxtF+S+hJj&p|vWuKXn7V}r;Si0V$8t}Ayl@gSg6tBa5gU%43`Kh!^mkqAf)81^g zi^G`d!T;@+6Y@bgX%h4n3n5%Sx%;IE(n@$l`-xZB7V*AuOYy7Wb_R` z)K} z9e=x1oGo^Pvd^KCF8_kUjM5V|SlUu_%o>^lWbe-^)9;pyXRs@$8JN^z2)!%Zz#~ji ziNz0W)wJCImP#SuHTyL|C}@(1sko6ansGKJ4OvY6+|-ftxJq<~fg!|rhHs zeEX|w?7o~4^5K@_r9p+li3~AIeLa@tv_?)*)tR7sHmv3Dtals?km40;$YFhN|xt7pNgz$~()o3Zsc!Ihh!_j7WlVn#7r zA`wLb*2hQY5!%9u1$VI^yov;jwnd#kH+)%py*_-tRv41wDr*qbkk!-E(+EqoXWzqa zupZ}Ru|0M&-UC|jJM8mMZ9Lp_>3_a&x(Os>xn5+;va>ABH_zt=YzgaGwBT)lWXD|E z-j}BgD6BaxC~lK+roc}f(;+>W+4At!lq9{}**$V3(V?CgKyd`n!B-wa8MfCH`S7nq zN*ZAjC)5_f-CPKXxW?R*pbMZ16(Xq_v}-F9SIi;Dr{5QZ5{V|F_yNvIjM!jHKuQs> zVkph;M-Gyw*|a1KNQOpa1tMjpA5jct@sm#t(ah-`94}Y5>aZ~D<<(c#m!a!Lc`&i1eBs9FVL4UzEjM#})!#fxa z;e|FB=ztXxyA%tKjTJ1GvlmM{eMf7LSX=O|mzOqt37lML4qhBbcx7?~ybgM?V=*{!EKY%)OftMr+IA(@I=N+ zTl<^DF?p2cq(~gp9MXB|Y?vM@NB2)Ie&%ht?}Egb^#nboz`n)^s*8z-bhBB5r~yu=NC6*dTQxZePcL5qz0p0i;b&w`waN_MHTrd73E?E%uBQ(6u6kPXm3%e zp&7!a#+H1(4guZ!kE=3V;j-mq?G?WRVA!gW65a_&x-DqFrKXK?M59H717oFUjch@( zjpLgu7f%v2bqk*TXe=qAydE0b*ZpPrDOh6GL?WMsg7Q7BlVT2g<#d_E1}?p&Z`~ys zz@#~+r`8`p@R+}JcSkK(oAOa`)+U-?e7d1~6Rac3*TF37$H|Q>1$0}HqsPP@a-M=< z-ljVnEB=POG$6JUH=K_lmcFYQ8xR)_Gb&@We{iA?H5w(R6jdV>=)F0Df>yk*ET(Ks zgA1AodQgft$2A6*vFKg%wkR=jq0zXXP2+v@LvEnc{WSgRS5$vi#2Vcjy&L8I-o@21 zoNpt2dVl%PlmZ*+2vxU;UQEQ|QG78jlpyc;+{UiZ)@y%j=<;wVt*3aXtvXfcg+BeR zJ?&_tf+M+pL4Jv&c8DlHVvXb^BS9i1oTws5hUYJy;5$U=;`+)`=AIJt3QEaJ!73pq z=3T)Yb&fVSK{u?OZsLsh$TOk_ap#1UW$L!_xS$NKUv@ch`dxaCr6Ub(?DVB-BdQUG za>Z(Z`mkzX8c@?w41p}G4`=QhQOj7 z;QfT0Tm02+H{r1iDJX4sHoUtZ`ybK4czE39Wo|Z&WZJR|5l`Umq72ctzBC*+0na~& z@$Y1ZxO!urKXJ~8c8O^+Jo12jXRfiY_xWa08y4F|m??rj3Wm&It$~GuuXOtje>Uzm z&oj?*kKKYBQxYm~OWfCqfE-bnqVZ?SE29xW36Vp5s~mPQO5(_!xc?n@U1V8d#P#?5 zsh0661;p~uHIhp#C%oM%a(FtUAwMeVvYKS{2Ro1qs?V*Q6Y+z!^z47SRrCcLcON{) zw8O>r`|7G}X^c0^X}ac9 z2cvmyZ*|u*RKiNXeN6qY>b?Y=s;_$(MMY^emAJ}KD0d#pkU7bmka^5Jmzg3FnJbl| z!H^*(MUs?xRusydAu2N=p3U)th3JE>#V)j+H0@9_C6^> zGtr2F2zP!1=eGk9g@+w7P^?kwjuvb!O8DA36&EbKxV7I$s3xDaf9S~7D78kb-F#T< zyNoAyTEXW6 zQ?sU|NY9A%V#Guf_LkJ+xrUgM8Si{21}U34kFR+dE-{}rzcbJZr;B(f{9{doD5Fe< z_MM%a8Z3NF{f@Fu(nkD|j*o|%ES?0VXkpLi^ILMaZIbUQeK}BBaZe6+()`0c!88nP zoiHt*QSDWi19`_XF?-~NxAK{25^m(W2l9Tjn&+CA^dE7=7!IP3X z#z7YJE~ORsjcG4fYMNPR>3aL4$^-Q)jDxfz+e%^hjidffeV78dwo}F5n|JUBk1E6U zjr{I3_b6|Z$vGrmq^C@=~f|^HeB#!Lm zS`hW<{*{02xH-yz&iC-z_|o&<4`2;@KWLf7S>L~zT)|v<*gvHuT+@1jB|jw}tR|#$ zJa!(|#%i}AXzCy?Oj2fxnv$|`r;kDlbOWVZeg&pM!!n6{KnhJCVH29g_8k{18 z2gUb%VJ2fc4Oz$go=n!UF8{=U9>POXGQ^U{JCb}p8?rJ2 z1+O3oO}vgR)cG-UK0?ID_xrp1K?!>9^?Us~9b=uo9_eh)J{?wgKu^yT{o_PkPIt_s zLY|T2wlfplUYp)J<~iNmMay1x(Ni{Bqm)-Sr=_^;Bmdn?pLyR{Zx_%$VXdXxI{CPA ztL|g2iqw0Nai$WYxFWn!O_55MNl(Zai}IV7PA}GFbu+xY+~R3lfwSQ7>T>ZCFBUDc zdQrnEBoK{Q+s%vk&?H@h4azQZ-0r2(=2K!>9;v3~{dj)nEke)VZ_{pWn!;!kZ#zBK zCtd@72ww}^w~KVrbf}mynU@C=%nby>aF>{O?v?z`v13fGw~}>(Qn!FhiJ-FFxb>%i ziI$Tou6O6JxTzoUFwU`qpJhDGHts^BW6!dtp-3QBTdS+1%*xWCF30DB*9gMG(X@p_ zyE+DbhncWP))($8%F)$r*4zDJnz^d{(59O{l2TP%YY(T>-8PvyN?X6}(qx>VvgXlO zXRe>L-Tg?m@`UnRv}BHTaFufJYi2m+rlR5?w(6ak1u(6LO1Jl+J_`12GV3fjejoR& zL^|ytJKN(QDNHR^de29@a_lxsO>}c^RAc+X&duS6I>^CYdMW~)n}g-HGWXX1oH3~p z$zCkCW^bwsv_d=cMN&6K%M{+g4BKr`gI*pArIvsr|a4N#?h(u&Vfs%nYL2L18zJ!$56eG zK)25X*~@$MR?YoeIZe|}b&?AU&&7B*el|;r(KSBhzcA>Vy#Ed}dgGxUGt1}KbgQ>w zirNnvrHctyu)cOrGZ+1QOW#sEpP^^b1^sInf~}B2 zb*wn6*shc8BiQ+wjPWcNwgzwTV%nchw(_3ZJfu9)Ed#6Yal6CPC~tyG(& zmVM3#doNrLtTz7ic`*4vx2Z+PCo{P^_kQz`w76`Q^5c#(ZZ&Ie&rIY5`Tpu^V%YQ5 zFD1_8*_V#WUz!F(#k)*~6t53u(j`Q1b~Yk3Kd3k(e(RcE;#)JC?vp8H4cqG1GlsJY zRhB9=#vF}~8B z!QuMw+F(Aw?SSoM;9%&b>n~}$_`{>V!EpUYzt;WA0ePaP z7S(p6dJHvu+QL9>^SPA6oj*P04U|Ei;Oxei4xSNAYwQ_`9?D{E6!K2>+rU-87cQ^O zs%Wgngus^@B@fg&7ty&4^R9#64j*fj$T@jX$fLzQ^@aG44*A%}?v7`5)NF)&57`ar zx?F76oRch@z~jH?8A>dsH$-D{!)SkLD_N~uWIiVAJ9)&+WSekec@hDi-y9on+-F<4 z-^w>IJJBRO7SHif(bn`OUuA{*o(P2l#sK9Z`f-5!1kIn{KEG?Z~u`NR?0sYG7EeGU0qE5iMKGG91rmslP?3UX#?xMY?h|*#bc{zwjOd<^+&LXu&uRb58@;P=V`82^ z)0@lVdj>i2YKOvhj5lu4s!{qP`1}lKc~)9_FnzynaeHGw-Su0S+as?$G?Jw&5SYDS zS@Nviy(Bp6ng5Mi<(A&wqjl+(K`|=435xxXuWCwbA6UyND~~Yq-PZY#(_ggRnnyn= z(yirn;GOq1g89}w_tLXjpJZpVB8`sR+iAjbalrIYI*&wg>Lru)HM`*(r#CuUN`Bje z6zO&doY=GVhyKFBZLIE+iJYzNaGUyQ!J;gfhVo~^h9k7Wx3=>No;v1H!$v6Kj0#?_ z&QbB`%J3kQkVq3wHl}Ao&86g`B72Vq%o4_G>c#H+LVMhho%Q2yVQ1rQ%SLXYlcRR@ z$gkP(aR?i1Xs|%fD!wRb&5ksQ)aE%FzN@~rtKTIIhT$@e5}*_M_HXwY5 zNR`QW*bD4}O6!=^%izHo#vWFCxZC!UJ}y}9`~mj43s0|@Tuok+<91AEFE5=@DI!XU zxvfTN^9grrF@MEAdJJEe%uzL#dl!tF%0HdDd6Sv{^)X|*Pt0Sz^tYs6ytENt%XMCs z>-+Z;o!f`Ce9sq;w|Bn!l{(h3Jz|LakX4}5EMk7}#kvs>_rBXA9C5iSuNQ9CeSSYe zyDj3Qx7(bEggD{Mflb|PIkyNui*z@xL)kLouN#N>MkTJld71B`|NgZeCB}7o`HZYZ z_gviWol{ zK0W2t)r$^Y;P249)^yliBf{4z&j?fQyIwl&=Nci~v~~G!cWr07JgCfzjVuh|>c9T+ z(8kj#JX45;v)H=&UF`LN?_oj7wg&cNpf43Ns2;D?VBI|zAf_RTa_Q$lG=?XzJTdLD zSR3RZJh*5WrIs)$WW90S>C2&|!<$uF+Vh)Vwb&GRj>K;%qs8uWJ;UR6%dQ#LY;&}j zvu|t4#Sd`x;x65`b8*jm5ZPbdIG@~bIP~RqRe!rQQ=lrc#$!*-?*1X!h40tm^t^Qn zjYi@;6Q`;*br%<2>d)$L=!guz@dKUmDT}dxPf4uYCa#2+flB##AHP1!XaP>{T*{E- z;P;vvr<3lqU$?qt(a4M|dMYogJT3GQ|FZR|VdzkRRRp*3t@C-ugG3i&E%fbAnqAm< z?EoWiYB#6wyMg_YsiT*41CIS;*N_uN=tcJrnJ7! zOR^N?ZgA&o&n|5H#hVEzPcBCAOR2xs@-}j_3^TvL@y9yS^KHN|;h&#@3%X-Vs)SsU$ zi!&b;mL0r5WYfRyawE^n-SxB^#F?z8pN|Qd%3XdRlk{`Jb8mLqX_|=aOr)A=Z}R!7 zsjA&vqvbCPV^2h?Cx$8R&p!S^aBThxed?zDLh8-B!-`hN&uE)fR;46*qLA*7uDYyE zW!(`&Q|uNmFWVHA#^yB}#i8tQGFDIdvG?;=`}6L*s*i3iz4Ba@hU@VGS&8oBQ5VMZ z+{1*|O_wLX97tGvTs&i3SAX(gu|ZELQ)^hEsqvS3w_2a^j(+({p$UhL2 z2`+CaohB@Bnlh`Z>xK+^>|ZNEkGg&(s_nbYs|yJhA8$CFN|Af|>}sDftgi>w=lXto z-@U1*EX8)4wr^f)NwL+ptCGG{oZnb;H-WQn-~0Gm$A<=knXImiq<>_&A`aJ?+T8mGWXuyn*L|frc?(2hCaX@%dcmbu%GXd>3Ng4kkcJw zY2(+QiyYo+_wBK#R#0gGr@jKsv8VHr=L9Q{w$;P$_}H?Sm6uQ3cK-UB-kLkYWAi#n zgzm!JE2kRwwIW3UpTd}0KKcfJxWVq%pBbT3`}j`&9zLYsZPA;TvuaAr6aC*uosqfb zQCFnkzwZ>D%NI?SaaUdt^Mzta@;+tGwkU1k42Ohlou~({ygda{dxf_y3%_4$P{u&Am3YU4* z&XsRSr;C4p)4@0iphhxOBRg_xTLN}_D+vvJW6(|++Y)H*s#r4eCYph;;{(2OZ`EZw zpV~Kh&v$6F)!N9!#GShNnUOxlSIGLhrGHxbA;BPH*v!QnXF|kZj#$sBiazDMwud|W z=Vs;?xX9e8RM&LzE8g4g$7^RSh^C8YeWhdbXW63WS@OoJM3Cm*)(Y2Oa=d4*`YV}P zp3E8@IeJyCgll_B=`Y`g45Oj7uDyu4ieUU&rKjqfR4yZ-8{PaO4XHvt>49z=eGL^ zHx)1oN~3r0+;FP*SPH&b?%@ydI%DO}u9~M>!kzfM_I95gh@@8&^H#Ncw^^<@gPoDP zDdpyuy5r>@!!MP;HYBB`ao=@nIw@-XBUv(bn}h@hif!EJkXDSK{u9mArv!|iLTPJK zKts^BtI@E0advwff~CD(NqLbyM#!&g{Vn>5fjgrKMlfgQR~NpY>``)gI`6s z+dA#8cfalBiQi=_k`tS*X&vxFjs8lhf$CfIkLb8ASD28O1W&52PQHR2B73f+b;IpA z6}`wIQTkgOOX7=Fe0^JadhG5Gb+gQLKNP`@J)I8gHs-Dw#>WBZcO>0sz z^qx=UrTDq@y7a6QeLwS~H6b+rSiF8=U+TJmHT;jRdo^!5%=ANaEH|HxJ)vOn^u?Do zVr6cxn?I^rC5~)trE6tumD_c?XRQ$4_%go4iB&dL)%q%iF-2A3@$(~16{aKV{hdLZ zbAoi=2YfeQS4QyS>oK~=75uT4R!5oBHM;TVN%d!ic{+t`+-19R8y^ngN{=)ynC;4b z<90sAq)SFJVDJ9*4X&|9c^vB9eHKVzg_r6VW=d@M`ybRurjDt#Ze}gA+?!QB$+G8O zOG>Ro@Whmqr(0$e#!~liyd2$JZfs62yM}Sb7h~b|%E>|8&9HWXC|i4W-1)f5g7S$) zZIRdh`_3D0xVdH9_ywyX+iU~D(r@ctT4JghxRP{B@28rsIc(juQQ7qo2Yem((1RUj z#$P6COQv&tZ=CQ+8R<%W74?2le0W|85iGpKG0t{dDb? zOO<+Xg?Ih6&2zc4mpUVc?BC9s)rRj>A88y`OuD5Jb33)7n|_$CdAJf8_U--C2L`XJ z*o+uxuhj-9UyA(t_T{ z)SIWX%Qz%{-OGTJp={4gP4a&p^@EO%P?jt`BV_G0?=v=`5K5(K*> zJNAr(br3p|I=l*`$`w-1eQ#mP)L?k}Wy-kI+c@v-KGhTrRYyh?`|W~p7Wt~~wN>9* zLcZtF--zXYbn`5Vowh+8G2m-In@~M1rn>kx%15NoE!Cnptg|#t@DYM+dh0}HY@(B%7$m(utD3X zZiqd7H-88}zv!i1k2&xyIRerZS>-vImv_qc#^)}M!VVUg*?Q)feF&Yrt9|&DI-D=OvceVUzVtbzA6tNYBiS97bUq>^4`9*^ClKJ(?jbw zs5h!u7};Nsa^Hm5fQbH}YL&Z5M%gRr>+7s%+~0p@JIxk^YB{loR{Q0<_w--vi}NiV zX-8DzExmtU9E+7UWKZb&;Lc;%dINU{s-ix1$v;uD2+aN(#(aYNEcH*F4 z+jY*Wy&gv~DM09Q7Buw7R`ZUwZCLdPlzi@)iz<|m9pdm= zXIPGfHQ0;jo4O8h_lL)&$lcrIz9ppSv_QyRjOAuQX|H!{-p2ad%RaQ^mPwC&N2?cZ zGQ%r=DeWyEdc$ow@jKJ^8^sgs8ciT{M?@M=$%iA7{$sIZOkHx6qyzS-X;X$}AhfBvV z#(e0V?xm}}JKeyYw=?t7oPS}U-^Ima*LgEoere2vJ_yMT-c`DIEjnpelBZR|WP#}M zS6UtXehxaeAFXFaf>Ro=wpVd{+xN}no5D8_-P9okuk$|77DDbn>N$7wekNV;G+Row zM@;scS;a4EUpNlP=1YcJNxZn2KkT|&;p^4O?8M^XJ6;dx>>{GIKdPf?K3|;W$JI0h zMeHPe)4*Y;Y9&Ux_$0?{>l58eug%3wrRxO@rbMx+i;4ecl3xq zs~WB6<**VpRLswoM30!5dZknFdPBI?J5j&VL_Rsw(nRxtRIU_$%gYU;$!nEh2frVG zyW?utnhiIlt=0-ya`DAXu03#PM|8p+*%Q*q*PjNC9qB+?1%@eh;H=U;exYJ=;wHJ3 zZWi#^2uNIi%48X)9;0kBt(vQluOsnZ&%Dkwp4+HF{D<&vq+P;ZVmHKlrDe5`GB^aiWd2_hV1s-k+$wor`|F7k=jsOvKUWLt99o z;xOan#>@Io9Mxp)jM_ebTv&4-%tT+${lH)?Xf0&@Rj7Y5K^vEEU6=8CfG^Z0RygDO zDMYS)cg9T{6^3o6gVtq^5U_9?6Pf08o78g228;jahZFIVYq>)0O#A#L~2I&mR(6_=*w>&tkx+do?BbxhwoZp3} zGj=;qF&2its}X+$P6|jJ2{8UBfh=XzghB+0a(4 z`RX}wERayA@7T8ellC39qV+6yCTZcprIy&Qo8Rxl=Wp@N_e{q`wD_=$>Td3I>8iW* zfI0pFGLP}PsPM(Z+6gR{f=}}teePC{73QNxW4wam+J3AZrt5D@KOdlD39DMnEx2;y z)`ud^vsfCpY5Ba-!Cy7cRPfG5nCeH`&hxBq`oH8wCPZ@< z3I{H*_sz)iluOKobA%7npu%-yZ#xOcdE7UR&Z$L6wFa$;>JESWqri0LF)G~ZX0>0y z*9o@NR!+=tPx#^Yt-EtmPjljm9XRGY*4yzuHU63&&NF%#9w9d3*qds@X^%fE>5?|* z$Q%9j?R&$+CzK`*H>5SDHEN}}_!?gty>Miml!+q?SjgQKI~LIQjmxO_>*V;SQ@0i( z{00(kRm%dvQ)1XPh=?bF|6hl|pk+ zG5-dixz2p+(kl~5vpOn@4|Js_^u}xNmAYz5r4KepdSx=XN-ogpBP}-TtBu?-Jnj{$ zgXoZUNPXCxZuP8fw@c@p>G$-LyLyBM0tV?Y`gK1m&h$s6x>r0K_&chTlC~Ftx|;e8J&yCVb#L-%rL_rV^%E#Tk)z ze!Yyd^ge;})`!MTMYb)hD~v3BdS*O*Ds0|}bv(A^exzZR{H0%}B2vEXQZa>6FQW@- z0-_6xbSz&=7^#j6{dmx;bt@kLpA~}J zOm<%HS)ff3D7+UQG2PkpMkFsl%OKV6_B{R9xdDk8v00YWy_Ju;#>Rf#e-tr4+7@G| zB)|A(@c!axZH!@eK*X;ed-rh>?U@HX&7t+XCcf0S9F2>xIwf~;)BZS?>)Z6Xf7N9< zu}7H~b~10`ZTUyF`VW`x{4Z+skEyQErsqprxnSX7r{_OE8UHVyh3ftP{`r4c@kF$I zt5-Y`ZOQ8VU_9B1CpiQRL0qb(E+PjK&#_R`gP&l3Yp|G(_!Dfk1hUbIKQRD-2wk-| zJ$^Yk9_%g-nM{CBN;DVIRxz7Nrh$ zBu9Xa^`R507Pg+5(>x(2M6gl_}l?FmVRSkOPhqBa0VNw zFG0Z)%%y#e02E}EFFy%7O;R#A^agk=3>>6l2;f@=%kM$}o39h$AR$~t*40f^+2( z+(i-Z0wO@sKom)=BVGVp^uKV?02iFgk7B@GaIRc}yO@971r0@dYfump4Fks#B9Z_D z2e=?sh{C|Yv2+Uv#F9*ahk!gRi3GR+60jr$&;{7aex+=%J^k|IU;}v49`MkcK>OAc z?+~j2>l8^#6`@;Te=~3_)rp6Z#0J2DYLm1ZLc-%<;8;Q;AYtHGzQBPGOF$P;!>Kwu zm};22>WZk!$cdaVcXtI^W_;RQn)FA3^hZj6l{SNCAunqAO983?Uqsc|8Tx_+0z;xk z-Q30DjI*h^3(#~Ddz8%0tc;;=V?ZKFT)#lT=!?iZJDhO@1!(|51K-kcgi0~>5RujZ zYgf)%nVPH1ONl7JT*2oD#KlE``{fEMae)zE1yH~2&XFxRwp8T-35fiG>WmT{sj z{mV2_@`-5B|1M1!N(%A2b9(3}V29_(ek)aw)n;E|bLjtDc36oUn4WH5ZkWm6L0R&@S8G-&HzfF z7KK7L%aH~WOd$dwq<_~miIf5a2QG9^o)?BC!Ckqyg~PzL0{R}B7;5(F@3@D*x) zn=d3qTWTTVQ>*v_LH?wLAZk{OE9pC`zhPHMGaAdhp)$4PBc=bSl^|+X%q=m_@mm^A zV&W2SsO&9q(DbLgS+TjK{SJSJH)J*!^j#D-mjwA!YF6wnX|JN+p@z)vB1zMLWO74- z{3$gnwwE+B`tPY(Vh2fXkfe#PRn$Oc=ufFxvA?9Q|97Y%ITJ*=K@tbj%}@mu7OSz{z=#se`<{(a#pM{Vrh!~-*#0?3|ST(N^^`P zkH-8*<`^Pp#T=6Y6~DzDGJA}KQ`%z^8a@iq5{*;^*i;N(~Bz~u{NDNt$9a6TzDsukRBtwn0Vv-T0iMrpg z$xGQNB%4f9fK}v>g%E9flQwoWwsklSA{(cn)DTj#2%`wJ>8YfttCfR2DGUN5Hj(`q zTU!|MKR75~<&3MXl|3<`gg9g&&qzTMvxk<&)!E$G)xmiw@PdW{E;4X94g_0pKpLRH z3l0QhaFD$P$uDMSOwCttmjg5aZy6U2f;U*~(g~FX1#*^yH_%^MAYss`M;fXYynzfz zg4!o@2sofvI059K;V?KP;s6{i0EY|gCu5Ggv$+K$90Zf_jDWPIe;`Q<1Ja2sU_=-i ziv*Owi1%RjBp7r71+}4n|AL`#kQYS>gT#s)1~w!|Lk&j(!$Mfbz*!!vIq$@$hg0G>Nwg4-ay|C}{yOXrh(^4-I{raTN?l zKtN$WN*JUlt6-pBDDjFM2Hp(~=?*yziAP`{k8w2&gNDNSlrSp3;4xT8qsj3=9atz| zj2wmpc+@-~0J)&VBVeiD10=aq&rXMg&YQG0VS@6LC;dQ5eiPAYF`Kj1-Qt|128lc8zqOKfr3IAXXG$|hoO`q z6v*X-jM*wY0E4n5DPVYN*+3y7!$^Tgpp<98C>)erv>FeGgN!Bxi~t46$zk9QEw zC?h!x)IlYuC?qf(lso`-l}ZjEJ55;!3XY_-FQ5)QrL9Auz<`6Q4m5E(iJU$Z3QbJN zrGNp(tbR982Z2(zz_Tby8v$Ak3AuW!%ftV}`{L1*yaxu1n3qiPEE>wuT?GRc2a0%5 z!l2HZ0tOmnH4M~&gg#e7i3ep0uZ96dqSOVz1S&nkqCr1L@hldNr+gOFi>9(00FTn< zps;w*%TktyCqN0otLVdm&Xqz=K^+(>{RMa!O8RiX%2JjGU{o>=90f|=gF0|jas{-U zs?Bkr+o!4*hotNSP&gbAqSfyP>Y&zNfJbEy@E{YKLZ^YzKtb8yt9S+aEy#@|hoONJ zLq#*dqwFid$9XW&NQ(Sf2u7v9cnsjyYCKQ}g31m7JWBmV;R#?~Z1uAMM$KnDfj~(M zr~@#c>RDj$DPW-Ip~3?&XnJ|oyAgm&QYoh4O01QVtP603irEZ}?3sKn!0Hd^5XvmCH>IWJ}<;w#+3}qjWMiUTJ z`U_ytkb4!czzBj$#z9L``uCtbJhVDw)w5v81O=@qVbEfeRWN86MOiOU4=6OS8V~3P zH4F)@d|HhMj5Z}Lz$=DUpHSdYjT?c^;Hh|u#S*CdP#iG;vAR6aH&W4pLs7{j7Kfqq z1<+U=7@||shr?0H6&9>Jp~3?qPRVC19vDT+^6+4AKn254=?4}MdR8ht95nmB`hD>P z%DxAPDV4tqU{rntB+gI-Xmxo6sa8Rd0@hlERLn(C? z2ggv^2pkx!QOYh519D!uIvZQrnma=ai!`h}&7s(ch`NIV$irD)yr*Dq;Q+3H97D^m z6l7q!Fi~lOGyyInjl;;GWzjfEIWR!L5~QVMWiV0%Ng1THIOD%ZfdW`E4yMwU=B73- zXY61iz&8TEF7R{UXep5VgTqV8$l~OrFp^Tz1Q`%cf}&3@uEx%;#4rx9C7@Gb=cQgf%%G#S)0@MH|=3dSd00A&CNOEfp9iWb)0-u?qJ(J0QFif8IPXDyQ zzyyRnolMMZ0YFkyfTgvAAo+DyA33SDxgfbVry`4@lQ_W2TE^Q2pzf`tVdiaX#%oS4 zEJP~c$@h=I9so2U^|ZHhaOLw9B>yj7zJKz6rkTk}{|f@N6(s*(PU$GBkcvCH07yBR z*cr`OSXoKAxR_WuIJvl38A#b!SlO6a{+(QmtQ>rtTzqWYr2qRM|7Xp`+=5R{Lh66p z`Zp3Jw*ms4_?VeJJUo~@*qIz%ESXt(d3pcC!N$h;55ef_J zxBowASD+f;|N8s?N$jfO1GqZ6xtRUiI17sZm~!G1cLA6H9bGgW9qs-*iYiu) zKu1?AM<-HobuLm`ZEFW}M-SKU|AkjngP z0dTQ)2bfE_INFo`*OK|H|3_cArT$00|E+8OKl{S+Kk737bB6gp8~gv-=>MMjmp%Ux z|4-Wf8~mTd2RQu8c9(x?y@}8!4hAleAS)rN;kkCu1Dk3vGB3Qg$*qt#v$kZDriBKb zJkA?MN-09x2%Z!Iwo1yvD<6o)%VSKyl0RXb5;{H+C<4cTDvLfzP!iXa;&|e(x%s4| zQ&Zpf#ed!HF{>ZGbTPfb|K#qW`B8PIy#yR*f-M8#1q%nKzB~Df_KJNk4AX{AV@}+Y z4_197+}_2UBmXKJe8a`~jJj1wwZW%I{q}{Jime1aher%Y6E+7oczZH9k<}^T(F=jFe*t#kY6@7ga1BOM89TTF#}bgnh}&fk2H zB5`k-j4=>)-oqp(L~gLV;tA1?fNXgfYJIZ=o|~0D%K?MZPLpXklVisue3Xk5u37O2 zL9-*qNXUbBSUc5`SXa`7N1qd6c7s(|i#t2AL^L#`8qhPr-NDV~X_1i(f{r|>WbW~B8ZQ^;#d~)@m>UULKQkzog(-DszEa{L!r&*=aCNEsQYf6Q2c}+FxDJGq$ zq9?~)#u);5Js}8aXt6_suF?RtI}(4Z+joFjtyJtQ#(`|ZQ@1ZtI)ee7@VCAGsVxok z5PF@Ro9yt}OcNM4MOemkkIQaA7j5_k)}S*XIQ(4L{fb(kp_fCU#DG5IGy!aiDr7U5 z_yo5iJ1YDTsF`t!s`cDy$|W+5X5-cYiOMKXI{KG~^A=LaNEpq#2f|*cHWHnbE72D` z465;MK6K{SHB_eh=J=tB2oRNUpv%YSVsLL&F7TdIw*qoC5aOpoxobxdG_Fwols?M= zX@i)xf}X~<7k$3W!&!q2lv0qbT(Lmbh~zXp1*sgigGri`GQ(2#%}BxGpv-quK#cOZ zIPQJkz8CPv^GBMT?f{*S-Vg@OW6@QQ8X>hC1r>yW&C+7N0<$`v9CSZlAP#3U7YCtx zt^%^-Pfrghl7%df_M2Z(0qv@UNN&tqK1@d8<>7?&Fdvc)+tVP>Zqd3*K(jC6)JW5f ztacRvCz633z%L3@i3y7+8mMF*A zMx>iR>?KCKJ3qM8-)ISC4r5tMg5w05@W-BpkBW%HG1{$rIRIq01~kVEmD3(zDSNYT zdgF1nrAmuaJVT%Kee_Yp&^CT2(?D~M3gGVNMxZ#s2Ot$ws+XN-TPDDTfs2>!40V2b zi*Wz)CH@7lH)PzefTsd8xv2xJhnvvm2G{9vIWwTcg~$!wj)Di79Psj!AcyUU5#b6V zQ4t9ty^<2fgLy6r>Rw;0m|XYNb=lSCPU*z&%hNxRF)?;SwDs?td4bQtbwF63Rydt~ z<07sEYq}}G^d;`qH{+vu)tcHMG2{cw3#}_fPpxu0uGW0?(t{sOYXlxrfoG@bf%g%n z<-y=*wZqr%`b={mYCDa!h6N8mY`3&qbjcYyl``xCyzae4=MWb2?ub0YCj-B~TdHtd z+2ChFA2CB!eeQ>)kw4`Edn!kM9p=(Q~%Cg|&0L0;k3P>NoAf^TSA`V0|Tp`qJ zIq(@sac~le;b9PwzTCkY2Ji>4%Is1!{yvP4hJ^69Nd(%yRoi0=Op%B*-;ganmo1wz9z4= z7j)bvHtC0o5wvkC32h=&BB6{i8InR?xJA~Wz?f!8O>pA`rnwuyXmBZENw6vLOFHEZ zesfMw9LqXFFw+r3Mh&Qj=(pTQ)z?pOJQ8R#s45o_lVxbbrPpSz(!S zW*PGkA`ZO+TkP1#=hwo$J&`S8b|avxeX@B{VnW55kk=#Lzb?kKlxcyq@z%G8}0;V2$iLpp&x89g=`cz!-7%)fh!p4a(oFy~4_QMTim;z_92uO3 zdKs!XxQPp%(;B=}G=vtTA4K^;n%sv~%*}`UJG`H(CHIMzPLJd=l7Til(EC!ycvJWq zju<$NYT9m&#QS1&J55jU<^NXjAw6&wJBm_4P5`nr*t~69UMSC3eZ0Y2%HeXbUJIa& zI?C@2xc~mt8VN$MzhUf7&cI0hPhE*iYbP6cJK3`yyBzVl9|*6 zC*Zg=#z>~7QK@%lIxB+s;jm5ks0mNUqTbF;5hc@NUO1GbZP>6tXtr2LL9Ms?;j+>! z#OJag#NPF^uK*K6SYXF{1=(VfY#JI031-@v=mF*X=Xc@Boq_KKW&S9rt|D-ELCPW` z2H)$S^#u*u{Y?*nK79{t%L!4eB6AezSCL^4P&Uj)86c$5AB42;+=&@rTg%6mp z4vD~Z#;x3aL6$8c7)K?aD7~O;6~|;i*P{m7GFWJ7XU?OJW{djedd=QLjLPl6_9HkOc#dlZepMGQVy=zgjmWm#-VctZOhq7U<=d{_ zz$-OTSmKQ0=e481?VO1Tj~()StBtm&kLX)G*WSNWnQ7qMv^MmXe=cas&U;xnvJF_z zo@o%I4v$J%sqEz!%KfO9>^d8a+tCoXJyv}j0#R;@BTsY1!5jJPAC=AlfBH`SKDQhY zJDlrzKeEgZ=-n@o^|@~QV)WSNH|=sJMW5@tQ{zg(6ZVfF`pfsQiSqe4I>nr5Y&CpC z_NI^pe4F9E>{(}W?0Xx440smwY^qeCMu8)QeAWnyH?I=Qe0)w9OuL)`rl-nukpD-|p1cQB%UQSKk`V~Y&oXomI7rlNL& z1Ca-%jE$QeNv@@(}X*|-v2-AOWY@yZj1i8Vf2z{Fejd0QL5 zXcrQy=}p+O#I6#Q{4=;yF9W_l2|vR!g^Y{&=-LSe74i?fK{M52o7qoT0fBZ{rz_D) zQsX1fT-rLDB+Tn60@9emXqF8FH`3oaM2MO7pM-L|CheuW$6rS96JLe%pUTk?A(gaX zJNKQP_WW#!q7e8?^I2G_e+le0!qmDy9IogJx2Mt7oUUX zx0hXKvCSU|m5trKf?SZTu^cg^<*sUzaL*tX9`L-Mkl$mL=Oxo#&MeNgc;zlS1;X0L z7PxJ~&B^nj)yLuYIh@O35`5u7ClMpZ3iuhoOco^=FJ$fHH}iL&CRs<4(un=-Ii*+c zalepV`BL$(;OC_N5C3Q6O8oaV`k23K_H}FD)@c@WbJi#!BMq&xnNS~91W{4b8bU0H z<=6f!DXx74_PBqnSJ$BsgW$BcK%IF00e2&PmWup|^~Qb+s72w~k>bj{NO`cpyOZs_ zuAA(f#ts88Y(iv#CHdey>@2RPO^hnLefEHQA^Eg?{(qwUEwfqTvjE+6@UxT46{m!ne#GOJ};7z z5ifQ`wXp)Pob>(CA;6+bUSdjribWOG@Kpm&9qOR}T1pz^2KAOUUbOWK9`XS~8-f}n zxdiQ^@Rs9n`a^ZER9lv;wuFs$gHd81Rb172m35l7f_6e1^EmnqIo>5CnoQ;=mw=iD zcPOnPq{4mU&`2VcZ;`R)&MPDgt}7F~ID<)NtXEV$cw$}~ji^e8wNLdM!Gnu zSEH)93znGZZxkUEpyT3MVW$(H1>>Z!fU@SM89lc}%`h4EI_x z!eDgSd5P8LOpgT<4%*Gr6km$g>I{sR znEvFzz_BkzMC3IjAlgnr0aI0xH=-8XD}3!@#g2RA*WE*{MsTlLHT9aRC=%FOd$x$I z6H^av2V8q-7jEhevDi(G%R%#x#?c>21wg{*pcKAOlryrg4!}Cp@t|t2bCk;grA_yJ zOZt1p^Cc1gri;ThbVQAvpZo8nV~xbC;n%;u2O^jG9-7laE;Ef0*>H897rAzmT(X)L zr-p9Fvn$V|!L)+DgA~`dW1lzAyC0-mmAm+3%vn^DJkULS%9OkS6z&GMgj)2<}| z!zX3oE#Ie0j8=k{Te3#^*pCel#$LXGY2 zzL^IAyesk#1s#eClW?EzuHhVe3U?(ZuoZx#pwn{eg(qLeki~A;__L0eB|o8m?I^h225l2wXle=N$Ifc^g4$B`S)*O zzYc+0TG+xAAE5|g!MDKkQq___yxrLex{KM&65 z{>3UyXqv30GH{ju$r3JcU$@op`Fbo~#O<-cN+a;Gv5m6nv8>^^ef37{xqf}+3|hrV z$m%$$k(}y%p-Y*zYrBu9c|ZGQFo(@D;de@`(84Zg88xHNw~Ot(rTI&-nC=IHH%FR+ zl-T?ql8mZ1{g)9~d)+PEy3d8}JmKqy{j@{=>zfs=NITM{&qq#$nk<_IimwrM0){9C|zzUYmMo@sQ zbt=>0oYa|E=uD>896evxn?=A;p_@CCoV#MhgVk(B2|0#%Xl9DS9v@HD5%UiYf|gyU z%xY_@wXo3}b`nvb0IRPAkK{`TBBY^*1kZMS+9@%4z~yB%i8c(GHztM3E~eSHlWjl! zX}c;lK3oU_iZd!+G2eqmdKmkRoJhpk+cJ49AW2DHr~7$V`54G2f@P)DQpfDnMS_F#q0IC!bhhUgf$mdz`(0*a9up`^KeQ<-;~bY0cWMen zEk8M&#g@+g8raGceG83{SWeMdS|sq_NNzF3dcQyXse!m8EhVh?aFv*Zq0HwmMQfbr zIZ*0ntF@4n!u`?g{icc$pYNw9?l*IfGi&c?U6g5m-F+TzRvpcjBjt}gZO1? zU%B^rF8b2lYJJ1`aucQJWuB&_==MT=R;R^c=2lv<@6_X|_x1JMZAjY70*kWRbTH3v z$Fi;En$NAT?T06w!&xN|`5j&xf`ZHoSl=!&fJdH*IT$FOafCgx?%{XPP4@1Fum%-y4uh_W+qh`{3tC)zIIXw+ynVb$Ws>-k z`G{`^v(>)bpoT_11zAmcABL54xzr+^K$f!mo8-uzP!0;VMwo1brVScWQsJS_&Pym_ zEQvY8{Ga2MV6M^F`t-0CWC+AasfI0IWJLAJFwgFo>=G^k#_5?$ia< zbc|Ffan=`jAd2W@ckEtYQGfhh<{zU_{ZZOo0Vx5khKB0>XWl-e7GLO^N>%F7u@tzJ z$kG(^Xs4V|atVaw_p)KLK*ymY)^nM%Bn=jHq?FdbVaLZzeGZ^J_Fla^S)@vk3`3|W z`juMQJuv#=FX>1-or8u(5kvo-jHS$v;6)8>P0fhG$e;S$t*HESrq1!KKrjnkL8C&l z-UR~_31iVC4rD%0>VgcZiQQc!535HFxFsr(R_mr;k&fa_&=z0edkL7tVB_>o&)h% z#YBgom{ZgTKew3#TXklzwK*tGxlWyAKsMCA%GOb+t;Y5jnvz!Ss`US+1Xqan{_>}p+y@@4h zODBl7toEHeVlolq2^v%ifLW#@)}MVk@95M=p?#xm*Wkx-48t%Y-X*6py_n&Dx+CTh zFg5@hCXAU@AeXF%m~ccbJC8TX%D%ftRbu3svzTZBuWh*_#0)8Mr3XW<(6h-!{hv&q z!l>jk?BSEz!?KicIdExp96P0c5k^UYrG(V4>T_YR2gYjXSQe@%+CzF$k$N`hU><3e zFetr7-pS4sq|ETi(j>@aGku)wm+q>Fe-tQi*~-CaenhJJRi>Ut%23)J-k(aKhc|nl z)L+RULKV5*Tc8H1(5lUIaAeFKWBBoShvb-QYQ8Y|@)3l|gSz2@nJAbPmbL>OeiND; zH!+Rc`uT*?Cs)OyKH7vumc*I7tE_1$tUBlS#Y~2TY>KKOAW|pqY3?mQ8e)k`TJNN0 z+`}Qr_5Q3WYN4nVK-u}gpD(;T<+7UoC68fnI0L~M87Q{NZhjptkVi( zSx|f@7s+r=vp@%VxC2 zcE31EqFAmqd^*I**IxcZ)IBFuW-=I2U0uzdWuU02X=!P>G|OLW&{0)YWuszvdA4M0 zb7r&b`0t^gjL+5QvpGLEe$T-tSaw`_UZ~OxT*CVEyQfn?N>dY$FEM$zs)AX;TZU;V zsfhYLn&8GZ49Kmin;Y{d!}b>?$*>$8Y5UnB0%ObdFI*IXzC#Jlc;fA$*;!JRRM?on+U!$iu@$ANj9& zI$COK*o{RPp>q{vZU3%4WS5MHO=+f{z2RV&ErK&xNmulwb(90DHMAh+>rGCXc+pN zf*xgVX{lVqj21(-%bP#LiA)rHE>*syiN(q3R&W*0#Tn%M>a}F!bm+e7*48;$HR9OI zYkCm*c)pxq=YX7jbi!)3bA`CD;rC=1GN9sSsJPV%s#LI7oQdbZ+Spp_T)*mCUR+{$ zdp)nBTWDf$kbNs-(`_iVp9}dLa61o4<~o=i1P=GT zkqvxc(!0!`Y{8x-okcXg#Y^6U=@iPi0?IqM3cd_?$|MhQpRW$_)@BCTl<`-Rv)!p; zy^#JC0zPX?rqob&EvyI|k%oJP4AggX{x8RP5U$yp-H13E^q?>6#{JmV1WW~06%%f#*Xz1usmpg+g$2pKNvhHMXqx0tNBbJ03S)Dd9Ouz4>*yAVL zUaBL2EVVLwY!W`OLop1IFX04fNaJ~O>nV^j5i$aEjtU250E<9|irFrZrH~aaWcREx z=57pThSgw4jevuZFp8)+cU)7O$JB13j$+Yd?W74YKx%-3E({kHD$Ww?*CYEoT|69V zi6#0hkX5;S!KPATNGA>)K{*AH;+xd`LlIafttXEWSQD=?E#4vYH&B#9(xmK=If4?N zdWqzNeB%|#mRci1+ocwXPQvdSVk zRkiOUtyFl#GwS{#mIB1)i}NlJ_pkoCNSdt2V&lulnkVC&n6zL8t-D){1ZFT=c}Jky zQg&_;(`(ClQU2u6i+nR8hIMq%2XTd_SW5 zQ>n~&C=NeYE9ycC_<|Xc^)E~L2o5pB4Vc@hw1RJjvqT_}g*kCHb8_S`l>S zp^~*Md?yz}^g9da8oa?ThRi$*m9bQ+D#r1b*eCF6fJRV%Su&iia=feo3J~jpf$?-? zM=qt7qeB52%c-1#qLuE)aJ^@mkALTnhAu@srdr+jdFRPJlZ6TReqB=6#s~DE92ev_ z#sj-_%l6+Pasdt9ifmpgJ$6o+dOzD+sjAO4fY7|IMkMh;wq0mnuDrwwoyh(@upid| z9j(W2X&UAuYIFXawatN?USFj5Tr~l!PEnuvSQQgsCMO^h<6u6%9sTe!b#2MYW}Os9 zK{71lL^AL>$$MWzPa=gtT1@$I!u)V+KV~BxQVY=FH&F$}T(8$`QvmKUX_V0j2ZKp2 z6@M$GPgk|gS%2hVS67d5`0~9-B5<@T-=Ovfx^i-tCNo%H;vb*EB%q{u=J@23C8Lf~ zW4U}Hd@y%r_^{NGX+=(Yp{V_KHeuSdDfqC#K3s|yWW^=GcGeU zr*rH&EhDfH?ArY;Wg-T>VmdaFVbESj^%Wr$yUnUhZpw9>ODDB7gN23mgr;ZxnH8~E zK=M}(%$W*aY{5r!-v05sia6`pIiWD(clA~SJR#v5#Zr>e;QNg?h55qd1NW+E^Hf-B zl@Mq&aQLOEK<&jPEv-?cnH2{OcK7NN`Kn;^Bfy9`W|JN8mb?eVr8%R1vRANJgF~0P z%O>3^^GjhJ{%Y8)L4_r7m4{I7Plf_H=ual>$xXPy0wUNA^&mo12o`iEWA%f|?c<*( za-w+CmcC!qH)eHPEd}r_AwixDRg+zE5%{v<)9hhZ=ZqS$9LGg(^emCcLM*I!=m>yk z8Dz}EMHEUNwK4bvp<=9H%;uk_2`UClpZfy_$s4Lgs)?am(}|s8F1pr1nzW)6+Qf|t z{#I4Gfh9Xt#_c%fM`}d<>bVsqNrsbtP95fGUVmkmA}F%^J&Td#L&z}XJs;112_RKZ zM9R(%HbHR7@Nvw^s%TUCl2uxP_Dt`wyNTC}VJFcj^t=djaY(BhhpLcMUTk5NBRL#o zIm<^xI6PmK@V+bVMc#o@?pB(QfA$X=_f5O)huVArCPHbiO$*bzTd|6fZK(|;!%o5;pqV{x ztj-}(GbO+#qHgiKntSD{g%Z=_<)q_<8!5EyvJ|C+maqk;D+B@~fau0-ae$8qT;aDJJGqyb6u$x812F&GIENFjKf ztkn*X)1~^HC-hpVv|Vw;=wPTMg$qG(nf<-g>E~R?@qt8J^{hzk5Q}*xYJH&)mLe5- zIA_qS8|2t^aQKv#F}~D>44qdQ*k_guSV!taHbA}XRq&rBQ>_|}_2O>(E}CZPpH9UL zeUy}V88{U&VcZA;TxC`KaOaMp->FIg6k_k_U^tTby3u87vf24EDQjJnfmcoZlnn{A z;mzf!SPi;qY6Z6sp*1oTbcyEhDu|V-^{L{!c4gN~8CzDT-_*Dj*zxLtw8Y(%`O_Uo z&_g1)YQYvJpK+p`yQ1Qt-0$-_E+E~jqfD|aG#%|TCw|B+2hZo7mCW4^4WTZoLfyzV zD)8`%GhHlYDmJQ^7NS}TJ03+N9@(q1!=Kq~?~eElU`VW|b|#GZDe`L_h|UYO;?th4 z&AqHC7g(o+EynYJs1x$qQCZGGNsN-Q^uz2{DZ5zmDIeG$djI-nl0#%Lu_mEmoZ(L> zZGs=FB+s7k9)49&N1c`y;_E5J6L}U9p;)p5Mv@};T9DPVH1Xb#dL5Ne@k;MT0q_=WEX=}fV|L4WIP;k5&!{!O4-Pr}KX)_mC5 z%W$FvrcoO$mFIb(J2|)z{}Z`agJFc4QKc;c-{D2Ytgl5a=aVN;^j20`Typ2g=i_7ul;pPjH zvN<9-OpNhm6lkFxLDm0=_2|!DsCp@Ttx4FsbEMgen#F zFOTqj$S}C9*DNy`y?^!zeF|W*?N-(J3XxKAIhq`bGN5~1K1!O6#^Z5Y!~!VPKoES- z4T658lv1>EA>hBGIkJYq=MSJ4wN4(Ld%~07uG^`!R5_1h@j@lkz4)Q?gbN3Ze^a^B zrG(YNb9#rXYQ{QlEN!+WehDMFd!IeuTkc=DJ+CynNTbT zSCOwMp8p{N{w5QgFt>Meqt0a$AMncf;rt1W6L>lniGVHtdV-&dU&SW+h)#m_MjMzs z;+`1xEpQ&})bQ@KJltAo6@aroNnioC$3- z8|<{9ivg2=iCg(g2RSD(a#tWX{+ z;T_6qMJt}Exwf1{&id2$uz;=2pAR2&Qzq`nc4=5}(CN%?e{&AEv%!qWlN1U54nR=ZG2{$f8ueiI6I4!EaoI>dfopTg+ zcqkBEq6>ju1EWa|mN~c}92K{vqqCtG`w`ILdwTq1M4Z~!uKbdQ!T<44)ok=H@Cg?m z{Pe^36hsp6DujucEd|BGBXiyPNYML!Rt?7RO|H?4zETPWINR80UmD~x%QDksz{ro3!{B)nSbCLartVPks|q!%K#EdA^*WV%B~!% zRKp8c#S8O9)a_HOX|rl)5O22EO^#H+wc#CX3_EORsn+qQH`iyAJ?~$myHJM_sw0E^ zS4px?mzYXwp-`l>qD~YfnEolX#6}1FdlU^O!%1LBxe7~AlllO18VE5sL&vic8zJ0P zj2kfS@Yj(p#7w2vrDwRzE@qXttQTS!U<+i%<146;sb_~GME;AuL1y7e`F%v-9rv4rs;rJOa9ir`a6Lx0tsvKO7>zAP=0E5!E+gvv0*5`mH=n7>ci%K? z>+N0aa%9YAy&Pws<#|h0SIXrvxjVeCMTW6v!EE3E%il^M{27X&EO7p?Dy=AdbXuNo zF|3g*r2)l;k3{VMyc;CbT^0{2tT*ZKs z(yldVm|{{#=D({C0M+$* zpO)g}``%^ETwaF2a(B0$aH4*K=+3`}Ncv=;2h!pR-3-f4RoBcNt?+t`f5o!Vn^)Ff zXq-lbRWKXY8v*#etUD?$Dq+&mt0gnNRVL2=dMjEPm7^wX?T^$!ekiHhwvXQr=H z&nU|9rJh-;-KjDJGA3m-=CL=20uMGTF(v5;aMZ?9xJ#0sH?)hQL&EAZsZfkO-P-87 z>GNMkI>U;T6{U6s$Wt$r5u=sHp<3v&`&%H<;gMrz0AuV+cQU7l2av|utD1go(I`u_ z6Pi7vn_|KN-$AXp`tL{UxrROT{_m#^UoYzm|KgOeER^|{<8>=@vUcvU=6Efb?)SP| z&D_WG2C_Bsz0G?1x}9}%o#X#VKHt{wy_gMq66(AOe=^cF2TZIsDd)NkT5s3r`0w4a zYrj7i-x2pc`^wr*QM;K5`+aRDRBI2W#4z(+w=5fd*}R|_g9*Rh^mu6-AuTuBtuBL2 zUl^RVjKtW$Aia1kP4WkLj0t*dH~5Q>DR0-dzh+lEcG>P`YgQMb-7hWwxH^}AeV6I} zCeq>bmLT}~45E_X^0}WWE}P>yJ29*4J#%4r7P{GqpS^m_;i@(46UvY$^qXezyq%Z+ zf`aUF-YyK`Ee&_44o9%KPY}LARXs zasy`wo%b<%5^u0B+;%$~qDEuhB3XN9MRVsOqiqr?#sa7lDbv8R^pOp6NS*V(bwQ+wZHPdS8b<`n{)~Sgz3fjl} zyrT{&O&`lZwswA79&ZAll0{&EH>75$SaX7kCG*wKo3do01Iwb^x9UoxVHlFnLswtV zdH$$v@0)`C1&I`;?-FbYgLc_>G_Plc$PCA2e`As9@Y!*U+N}&~Ej8 zcfD@$54VB$t>n!fWP-rM!#(p+;|u5wavG)h@!2dP;NcTCO2Tw?`Nv$IA5(YUh1Hwg zY2!=VMsG){BKPL$0&<_%=is08zg<_}q&bTI4+F3)ghLT1=ODK|bc_lqnHTNlb!^$qIwpG>OM1iem*LS;5;TgtS?jKZi%SXpbF!0Fd zMiAn?aTchy$>zLSQz}2IHseE&To^!*+hFVUe8_Z4OEee&5+aYOw3)F3Fj#OiD}(Tw z-=9Tq#n0*$mYTt$QZgOV8c+P!Du**Sccc|6dG)9xk+Q2I1$Db^{!VF>A-3fNLCuFU z0gVJhkY!1e0N!tQS51I^mFfyB8P^BZ&dyd24z2+xcei9?Dr>ucb;ib;+?qn2?zvJw z?5G^`@!ux3YU9B;%{}(YQeP#v*B@20Fu3{^#AvVhD25bdLFb#cg@M^WPqiEj4{K zpVPFAt&e9x`Wz(anG}m$j`rH4T<#zIm(#9g7v1L-M`#3pYDhRdc?ci7-biYzYWl9) zw0}CEP5Au#pxMs%u5BoU@1C;bqHy~ernd~eVb0SSi0b!!fO8^TwYHQtzN6gj+kW3h zOL464p!|yx(-Q*{y{AfZy?SJ{E=CZvBtC*wb_jHbH>J!FH9C5C1vLy|^x^2@+#&_c z->&0tX;e?}^6!Yr%NQl7UqzGWmQ}x`=-Z=*DZnRHaL{1L4?uZQdF2JJlSmXgg<~?N z>LBZHnJ^5o91U)Y4mkzVrkeW%v6tjQPSx|jmmUpgFaMr^3t7rymF>{iPWDtjWuoNG zM^>S;EPW(3fSW}Dpu9|{h#ipUo0t?`vKw`0{}`avN9Ex#oYwdL%xRX%w*5W}iiaWT z7iP>GT0;T$FV#DV%F{|1O%!gxh_Z89u-)usMQc@#Lp+)iA=4Vh%9x}@d9yrU%HZVT z@X0yXb)}M=(81`!6GM&2P>y_Z6SIhg zGSNhht7t!}g{-UA)4pg?e6Y56?$UeQ1JQ?98@sTMM_ShE(&g-3O;{*}Z8e}c(7&X4= zX14)Z2Sn?;7;5AlDU;}`a~^8P-TV*A`dELtz2wz(bqUQLaYMy+j;?LmRJU0QOm{cm z2A(c~a_@!%%-b@!f*5!ZY>rWC-}P{86F6AZb!XX_&1G&vl7$W_IA}=udSw3bf&rv=5 z1)L+kQBJT>HQ;`vE3TOvGGT?KlS0Lsw3g${7pG0R@|Q#5rYrs^qRE*X%EFkK5uVZt zTvedkTrQRsnw?gkJ-6Dt8S^0~8Xn*Ne0|8)q%WJ{@m}shrgq$@;J8{}$(Ye1g-qao&d7~YRe32-*&kJZ zVc_ABVG{^Jtjd-)Ua}xf$m{3ovp$p{0M9&|`*vQNXAaQRB%7$DUGD&X?xP6X+1l&& z*c?_ff0=#eB9trV|5+5U7@OcXaG4LY`N`Y|ysA4kGzq65{U9@6Padi3d0t6T)&u2{ z1Y9_~GPQ%{Arf<$PtJA$dWIU>#&lwCS5-w>c~7iIOzW2=TE0o!(ODi}0kO7ALonS*__dMl+q5vsq>z8Lsx0 z3HYWi0i7704&u86Y4EH9vVLx$;vCHX;y zh=o+_`Ld8hHsL!Rn)W=P0-P4=Kw-Yf+>yH^N5-F(&Avh!(qv^Qr;<J8o?w5=R*Im|IZ_I*^kIO%1JN90O64scF zlXI|zfK!@%FJ~!F(j1(ZZF50xnsCY2KF_(@Vp&nt#JR{Yg0wKMR2-Gm#es+{+wwuJ%){5-ZpYH;n3_hOj6Zw4ZEYnFff0G>2k zn@Pu2R#)0vuRrVz_0f3m6h>TiJv7q)2>2kG8H)J2Z0P%ZZS-0;@)^pqoXvBc80ord zL>Qws`HL_ogbGwn2@MG07-)k(_gM&NaXZMFWrWlj09p*Q$Kz9Q+wP4AG z6}aXfIf;8x9;I)&ugE1TiGNbqv_Q*psVsbvXI4^F^H>b^jMf39%gHI<_g8F)Or<@S zM~ILmiQmD?>rp9fv=Eu~T8qnQt&a^EibTEKdkShV)X4q73w?L|Rl!snJ<^89y_VsT zQ7-+rKAS8qMEP(l@r_837g5-e%?suj8@D6N!Ydv#0zUj*x1SjJLhpsZgcxiwwcTVx zsFpI8P)BW{-aU{j-T8cyKHIbq1F{69X}khO&rJ40OPPMJZwK zw?_;zxj>MDIHi+0FIBj0s~}k_u8P2t!Xye9qQhfzO|lN8)6C37N;Rr6mBD_cukPo1 z^6~uLIBL7{SNsY?x&apY7wGi`&v#Co`B!=fh?}a9|>4jL>hg)UUqMD*l=Cmw5bZ-6x0>07!f~e6Rz28_rJVS zcmGvcc_l|_jHto9U6&C6$z?mq#81&Vd(=;h7k;YKVL&V;Ma`IW3ZLiNUS3yS12DTR zcx9!Ko;21O*_f*9ehIg=pTgcsXA!u*>FpJ=_K;B2)KuAXr_bRMe>VSDbva;LHFV$Z zVZqAzQ@6hIr}dcFr(ea+!4@`-#Tg{gKO!&m1D?G8_{s+&{vdrs!SztN+HT5*c>d?a zzs@N**F)1AwULP5{?^SaXvwKk#;1RJV7uFE7N1=xIzEwJKZw*hByF${>sRT^es@2{ z{4$JXHwKB4du7?Fg{%1!W17rj^Trf-U?8=6xa9(G9ku)$IR16+%SK#%?Us``D2z!6 z{VD}vo)_3Jy$-Lt>8Tdm^O%MI=3pgUrW{Q?Gd5JOWtaDHaj;DIe*kSjlE0hp(}JcR zintlqwbGi%qVG3qXn0Ihw!4parFHc35~8Q-k{uqoYU-G94RLEpr$#b@jE)m5>)S|3 znt*S1@8auT`T9!{s!8Uu?R_1IT$)968a7lnUtE`##j^?K_TXlN)f4o1ZN9GyV5G3} z@V%6Ga}sq#jnG`(lzU5BfGe|8;>qA>-IYl> zE^~1uy&k>z7R*#I5;F~&N~R4n6bS0c3~Fnz^0C^8og-a|d^8%EIAv@$g@*-$dOBmn z3d&jbx^}&BM8k-&4VFbVwF7R)ZWBFQtmbhex1ThUr%}^aSA{wg+4f9g?AVc$$Bndc z9~Y~-q9T*cWpnvpFtF1O+p9}TXD!o!RRB+Nx*4jDL=(M9K$W_t#p7|qpqtzCM;#qm!c-HK*R1GcmA|lkFS~MEM)<;Edm5u$oP$O8nX-=BFeF^Ig=1OlG zJ^~)-P}x@f;0AcucHS@od+xcXS4Edi13U)5a_qP<^3PmNeN8T%lihZZZ!7yd3Mswb zW{Aue-V*CY2e1y3a;@T2%KP*>;S>T~{?6AbUn5F;hDl5-o4R-#wR#2Fn2W%riXsf_ z+>t~)YDfX5c}`W+7>yQoM;85;XTiEq-|jNMVV7SnA&ov2{o-)mUb${bkeK^`AHBDn z#hU}8rtdH&9wiBZs>yMPEbAkB6p$7Xt%L^1cFj}Y{Qj-J+&WFKdK1I$gRX#5p7_eZMY8wfIMrj`+Kf4f8G%V$u1p;y7c0n z8?yT~m!%Ydelf_WA^8oLCY;ld`}YuA_8=?v%`05C?AYZ=4#-&^=E($0oK9iiK2@@o z?32k=UCZU1e6Faj)D~-0a*O*C{+&vf3~;#siwH-L}1>TD#CG)6lGW(u?e!D88PKnIGRedmi0Z6mfaDB4rd;S!zv%Q zUt=y=oudxuA6F~c9Gdz5I&%Tu=k;NOc54D{Ihe!*Njs!cBk>RlE!y6mo}8Ivd>9c` z2JSK2n@fXz0w+J<=eHDdU+(`)6?uuNofR1^DZUtJw*yN1cUa%%PMBLyRMBH83>cG? zWJD=`dst?G9ahDKF85Q0w4}wA>Po?g<@zyw94AM|urwkAUEY|B4Xa>Pn1Fhus#M&P zVyR6rN6{~}R%rX?M@K8Fbk`z@L|)TX<1CC0%bbwk%oV>{sJ=6v^m=>0fW^mxO6mLa zyp<1zgRxMkF9l1;7Jj*(S0_oaVir5=SQZGFis8umGRbw(7`$r>S^B_v+vY9fCr^Iv zx#tR46BLAL2GhwtPzRECB-gqudGgpXa%UZ`>t4zaR-z+C+EKkyM6q>Pu{SG%9VAZ} zst1@QTR>p#j;`s&u#Mc4#*tA+A=4*Vc> zcwaJ|&*w^ewR3;PGjL*R#O@PjmesE zujw5xVO$YS_iD(6Y@eVNyA23G-o;$60kVJrl1(E-X~)lk{gtp@^NV}ETB|^)DiE)H zZCPTc*3{&B8x~2ZYKYvO7B{E0vm1NdE~l@T(Y2GtZTHp6WM_NUJ`$C4Bou`&nSQy^#3N9m19MWRi6TzFJrlgX>vGAL;7_3xjDJO(%`@ zq_c|#O;Qz8#Tlfq4^l3NnmH0As;-x*p4|vINl&-dIGCEKZecE10ByF>w%N(JLNz6k z*r$vcM+e3jZs})qDVl44*klHSHPtmTlIa4nt#2SbN!FJ@AvBrR)Bp|)ZE3}HH>}mB zdTQvTy&W8R&?XLu2yu}zW(GouMEizS$%gvjEF@Kc?8*r1C=w4TMQA%B7%<_{m(KNM zQo6T68n&=D4HJ70VQ3xuZ?&~;(PcLjnWJbn&r5{rh+Pd@#$ad>mg)R%wrZSA1Jp>PlzaT8kJB1mcjpK?n% zbNhF?FD8=Z7HYK6KTA<`l{%G2$!*qf$2kj|a9~6WBitI|SwC^)?E?-VP?rFPsssy@ z2Audk!MI{v3Dx@vb+_#DC%4pK3Um8V2ba0)wb?@rB0E}Rij%|xbrEyZzm{F{QS0WL z&c42JP~y59f7Rkv?KJt&<90t_SgjG#STgrLBWr6a0#y~2>pHVMM?7dJm6<|0ei^v; zy601!;5;b@zkz?CK%05b5pcxcI7D z&zUoC#pfS9`#*m%0)d*k8qoh++S_g0-fO>u3^VxQJ8!_4)z{U+ENtG=k+<^)9d`7b zUtf0P<=3oS@r{jjdbmBp$!E>m+-oQAJTBcwLI#<4;pL6Z z6VI7@R#%T0TxGoSI(D2#UG!2-X)9PS+eWSV|x-Q z+2V&+R>naJ7tFuy^+j*ORpf2w@FS*O^6M+Y;bT)hX#~0d1h}T<3dbX9VhdU(i~E+LjaMSFy?QsTeyxQA5-}3V`?}#JI0zO zS2dDUOM1kp%CY;zE4#*w?MQA}+19b;>Bav%c&Gh$n{Wtmw!PsUyqo`gjE;RJrE%rw=b2d z8Qg%~4C7JkrIyOVIcFVv{Hw3Oe#1?-P8dI7`SRsA-*oNb#UH%!_Pb2WR@YX6kKEIn ztf`HG``zA#hQ6VGP%vyH`*MRSf|)$&ZSTyc5;@BT|J~H}nyN@=BAx6>4j(oIv{EW< zRaKaPU6aXFG!mLMYu4H4oPGRp$0k!wG#ZgTC_C9;>{mExb zetX5d9e3Jk*|M)LoOAJ?{`}~dUwome2zfsF-A}6;hK{bQigVm&g~|f)$hx0bc6IeN zkJ|x5JF;)PY=?$EWh#?uZ|kV5t^M-LWi>T5@4oqRHq$qF5E4kMVj)UGpw!?x8|tb( zqDv0cisSA2B|B)q)%Nx#s;esct*cZvhub@%(nWept}n*`1<48r3{VRVt|Mroa=?v* zQK2H6S~n%fk&A*~ht5g?g8CkkY{I5?s4DHlS;*ojW3AZF=@gbl!t^U32D~U)R)xQc3Ju2!i_jlP^F0*N0Qd z^w81cufKKSq%l<=fBNlXZ!I1%y!n|Y|Jv8rebh;3o_XPU_4UD}pRd02syTVvK4SXJ zV5}-$S*7x8Jqa>?+>itIJLF#p-=zqiGRJfxVNY4v~$k8=)AL5uUz-y zKVG_h;R9D)ehCcD%$Y}y9lQOPUoPF;-Z5%)-D|Hcy8rHl>2$WTvgXfE`%Ui#%ySjtBne#C`y=9p#(l$RnaU32wS zAiZBMT{>l#UEr!tI{B2TQ>Wf={q^5{|HI_%cYx2NdbS*Y+;O+v^T@0j(_Fa~4cMW8 z8TjW*&;9+Wmp)wbjlrBuDk;3aTKFp(30GCsVWYRp8xlzUhZhatgN zkUk_rftY7o;bWa-OPZ*iLGyCc#I(d&4MT^a+5w+ZhFTjN=*v&PaLMV%jF~v)rrYoS z@`G1TJAOL2bUf8_&&^lfbi=jBoHTp4J@#C1#rdDSzl7Q3goAf!X=}gi>g&H;vUJ(f z4{NI{V5}@EGSXL@cJ$1amCM%t*a5@2Xz`mfPCj$&_(_Z3cm)*4l26}*vz~Rv8DFjV z?)Vu84sRZH_rl-(`^(Sw-FGjzo}q(>wIhS-p_#Kz7&l?uob%6q{?+$Kj~y{)^yu4f zz47nQzOrIE**{)*>Y#o0$!8ri6soR7yENm-sV}|o+|kpIS@F&Hha7Z(rU!4nWkK7<)~N>{ z(%zXK*W7FvY|QxaV@8cV^Yqi6d+xb;^R7DL@aflHbM*uFJrqM*r-N2?(&@iH`M2pa zPXg&prL#RfJ&C^Lp@$u|X>5qb@l5f6 z4*nZ=z2Ji^Fab>+?d@#4;f5Q&{$@o}guY6 zx8Hoh`R6q@4L|IV18=zQnk(ncJNdLTF8j@I?zr{Vb1u9Ti|WN6BZnhzvJ2rd)b09a|4q&PF`TB>%7cZ{d`1-1@?;~1nLLF(EP*+`B(VNRMNv+ii zj4`PcSb?ocB_B(awg}`(YMCJA8;2IQvyyFh2j16R{L*H4!mF4u*oIXp#@lZ z&GdXGWm&nnWHr!I_7^L5MPuGKi_&cnn5+Z;=JQWpX>82rvKxM0b?udNr_DNN#OTM{IulM%!%KJum)M=6Z4w+8KoMoTBx8rsve)s*#3$M8GleZVW z`@uVeT>IYJZ;WW3Fk*1*%u~*ryu;2<{Pp)(Lb&Af>e`x@Uw(7^$c9`ld)LCdPCfpp z^Ugiv!;e0?_ntdJ&Yyqb^$RaL`&TC&4Ibu*=FumfJo~&0FK(u+w}yaiA|AQ<@dyapvh#W8Uv%ZoH?Lc>X2a_5SGTmEaKfp%T<)Cn&zpASVSuPrgIX-@bZk)WgX?Ny zktlp1na4zUY_~65*oqBvA6qxRcUXUVVM+u!bqyPZ%|R;?pnuZ)tU;*D?Uj zRF>RxuZYz(5J1x+B}_)Wq>aUNohJExGCi*9hcJYzY8w<+(eWF>_%vcxnn7Y-uOBb` z>dKNk7}Y$e3bf04SMU6}^Mf26)Ya48o%nLXs2!??jI&n1>smh%Gs{fZ%IEs5d}G|0 za?n8}5PRyOm-B?hj6zb~(e*0E$goO%^dLFw&iua8kJ;u|5!d=6@dh z=)E`XTrQK#o^jE|5s zBJVxmEGx>q;i@|6=FVYqGnvT=XJE*2h@xZ^L0wnGfXeD;+T9m(b{F(RQ3>)Ys00yQ z6azUk3}FbvFnOkPzVW20ub!vs+|Xf|LDt{9-`l?yd%ADmzW1DZs-Ex6A0hM&5j`yQlBu4W}1IM{O+3Mn^|W#ky2HId|?{`J&`sUodapzMg@> zJXyYc{$C$@fC1ON8B|17tOzQKG^Rn=laTM+xktX9n}2oN$3Oa!bh>Ww;>G{Z=fCi-cb?JRJt7w;2Lu>YM)_P$ zWidE~3W4f|XKdgHaFl>Mj3^XL1>Cs@90 z>Ejz;$&QRTvBdIKs})wHWA^MXeChK~J^S30mgbjUd};A&K$YYRUQ6o~xjo6RXD?W^ ze%+cMU-uIkz<2%rURgfa0M&3w?M#^3rYX!I4BV1u8iu^f97jQzD%Z>r4Md+P;TbhD z6=nFnlDag2X3xv=hUHF`YI;+hF)L^pPE1hEL#d2X`O9{W`y-^phPD}D_v!`lwg&gP zXYWnfye?IUn+^~%s4u8ZQqzf;chfDm-|^gwc5JFimBKVg4-*A^sZ6R&Q~}}*u1{R|gKri}rPI$i6Bb!EyJ*qktH1hWf&GLeM1&esieInQU)3`Q&YP{PwqZ-g(En&pz|hSAFiA-~7hF zz>qu`n_AmDI%ePZhkMEQzuwT;*x%RF*w`f3->+`{)ttF=-gn9Sfu9AbbFPItYuUQV6qY zNVjr@5{d^F)*pEovy#95_3cX+&Hva(u6W{wSM@N5(`>GgiKpa^yYh-FK6KR=@4WMF zc^>@pcC<>)kZPlDsbSa6TVGvXXWtP)l@_Ie5Ib{_)JGb=o?0bEylSohRSnS!; zh#NX_dpMVnk9*>kp5OfK#*KTn4iVQ8UKJgXiZV=tD!7_9>l71;iC2WmBHCrth<|fG zq5TY*LSlHH*WcgOMaZ5mvMWdS?(LG_L7@%Zy!XS<_dTYK)2#qK?B%5aa+&W(`yvQI zg>EsHOlB;SZpl!C?CKKPoUcw2JZZ_pfBEA{XI=ch)7KqRM}Bw5Z~WZw)J6iMP2mP8 znk*A0&-G<|&RM)-WU%j*m!6v)BbzsFe&e+*>8h+=KC~dnhO^Jzxns*MH~i>`6Hk;c zW7^DyRV$WWckOo@npzH9y9U|tD_(lxmBZI8yXb;*jy&S%TYvSNk$g~BpU#&`_uu~~ z3*G{G;>jo09evEMt*@&QQxbN;UFZ&1@J`8uUi3qn@JD-K_m z$~0!P+4aX9U*aUe$eOjs{QB3wU9{}5){HH$$k%^x?W0E?HE-Vh6OKFX_xIdu#ZsTX z>f;{X?^|yE`PSE7dE&80Ehqkg4}WOo{OK2-d%s%s7q9>6PdA*n_Q<1;zWa__FL=*o z^A;=`%w}JI?KS!8{`$a!#~pjj|N6@JzWx3Gxc|Wi=N&TZlvB=lbJgQTGaP3a=Hf2J@4FafBUy=Fgu)aN*cE(IbLXFS$|+ZV^zug@xWB)(ZGs=Pg}*#3}E(K*Teh1I6~~jpv>J!J_ML*}nI}OD?_Ph8q(WEqdbo z^Dlh=rI)?aP4O3d1Mc^NI!U^&;l6CmkzWU`E(`UW0 zbz5Uo<2SzXt@F=&mkc3f{83p#6pF!ylaD*=jCWe5DQnJSk3H^(Km75j8&2%&8AR0t zpD<_6>^X836^ccwA@NlHps}%a#?{nd0`{eNEjv%}Xe?dtAYeb`~^*B=#2q~$9)^|Z5+ndF{5otJ;) zim!j|%Poz~GE+U_#0{rx*f6JKWH9b50Z`%l;X`1(}R_CZO9Rxd#fSl2^d zY%n2COP<4{MgJFf-aELj%dV?mHt&$V{arbcFt|fqA58Er8(Zz=oU*nUj&^vW)uT%^VqcJ zLp;HT^M0R~*xE<7_nW&1c!?VgnRvn&o>n*PdY!Ll6Z6)8CYfn{;GxHTvc*Xz@FWSq znE?>qJ`cf9+)1`E!ita#xans%$v`U=#hU`SWC)msIeiKl7$w6)z5|Cbu^g+tjSP>-@04VAD>J1TQ)2RD z-qq<@%1r_Z2{Ip>i6#B6y|QFAkz_-rPGJK>WO&rI%_^VX=q3gMkH_uS7Lt_p6(LE+h#AS| zN^Vgwv$?UM{G*|~o6QZ&ldU1ySf`XeWXjqz;Q9WH>FtH0-`m~mSZv1hDKbCr+}D|@ zuWPK+grw1&n;RLn46~)Z39mmH9v*FO%#_ouuD&4{W@6^UQNvw+zqP43=IFmJOOm0% z0j9*ygf`z)h(1wm=q<{$b66xn)O$1ppEhmEaLLOKj7*!>($_yExYyj=Rx0^*bx`Vz z=0$H$uVL`%Gp7^_L4SY0Ed1der0ht*#7p7V3Vc$`mjWjD8vpfIUp`{(x{rM9Q$M`s z`?-7(y;G2OtPtT;S9%Iu6e^87l&WNwy{mudq)V>Y`t-)+tXc2baNNT$KGo?r8l{9h z*`eD3B59l<3W9M)2&?GP66f1H<9KFmpqhd-~jO3R;%dAJ^z;*W?RHbIIioJD+rEr3x={eA*e%e9uYTWxfP2! zj%~^B`Pe8AQ728l`cyKBw(_NsQP)Hd*i14egp(b~%BwFIy9|}yzCIa>j$@UIh0a1w zm1IhhNN#`K{ew`)VeYlByT7*ei1LF}p_}0j_73z%U}TjDnqf^pkwuO!A*q-K8LIaP z1QlgNgwix}XWzBATd6DW-rIvKg6-?-2088_p)ko5q>tIYJ$*9tKvPIAjL;j*hLm%~ zOdQP?LF);-V)8nt9p}cIZu`hbE`QfK=Uscv_feUPD`2xy`9RxI)Lg_DWh3(ABGKQa~_`yzQ#JJ$1ncGb0j>!FA_*dzV%fE_=DjNU zeboC`_+8vzxbQ`}=ULf-HA@idEEdUrSHOK-a|TuA3BXJxJ;oHDRuyfKl(MpI7*dfm z=LfWFAk~$-Gjg6NY`y>?1U_%bP&7O;1qIcFQ%~LS(n~MTn>!meg3(c<%pk_@69dOF zC3{L~txa2`3(qXWDBH3isM}C7v>^8a*F98Q3tl0`ZpE|$Ia#3FXqZ}9wnjCs?9WQj zeiuC&NWe^2zSn%wAMH*qo$>C|SFRY`{q)|U6m#N3BRj*<{&n+`r>%~+v^wOFj_o5S zZ!5H9vq0b(86mBWQwg zdQEP3Wbtmlw#_zJoMR?9_*)jbqR2g0l>h;?KqPsfpT+D`mM;0g@v|G| z#y9)ZJKa3#8K!kk?-BEy^Ny-BQ~ji^Deo@$&0`H#n#iK^<;^mkCkclP4v|I6=!`?I z+`j#aefyr>^4dK;owr)%P$nHh;>p!6gO$F}*?{(gQCb*88~@e-IY?O}pcaK?)M8Ue zg&H=2N7a6{g2h1wR23QXzdOw383_hfe$uj2Fo?^9}H_bV*t z-->68ir|8=aT32s0+y$40K-ghE=3x$mZy;`jYiR{=$T4u5#740-me}M%Aiq8*Ff=N zIPHB!&1Yp>Rz>VZq*PD_`9Rvo71vSeg@=OI*0}P!79NOLw^E<>z!l&2kXi-97m?g*F1IC{1#FEur~HIOo(c!;>ga6P$(+!~$- zrc9`bh<@)-aYKz9useG`wMCvc{u%H94;Zs)GMr? zQiP2p1UT0&x9AP6PHal?`ITQ0xVMI(j{-WdEE(6xHx&J%m2LqKBaS{-7P_LG?uMew zx>3IM+HzTF=SL9o)Kpn{IB`fJBQm&pyi$cwE48d27;0e;hCoGdMghu-!7O1FWjP-x zp>g~lOa!U2K>)dC5&D8DRc`co)FW|F6_v4T;8-kqs;5PtRIH}M$YKv@mYyf`9otaOd&#dK^Hrfs$Cs>#BWIJ4?8SKI6f0+JT2*1qeP-wL$CD0KSv=KQRmyuk_&`89`KuR2N6FMmPx2Zn1^!cpiMJr=L<$(-*H|=*{ z5wQuCCkl$B8>y_z3?Ksd$4Zyj(mmvWac7MwxyhLx^)PK+RrM*_8{_z)gW0YCBP0yC`!5njI*4 z0T3f-;TnY3$kSjO#$;8K%1uO>RWXCJ2?*nHg=$fg;qP3bT;419%l;EO1PN;VGlLYFePEq4psIaG4Mad02acJlxAM0x|Omy=^6->>RFK;bjWx=6XZAH6-;AU!q z2nuBMK`w7JHGJxf(>|7ICW9kn$Rmjai8Y8F97u(^#0Ly4K^Pkqhw_(ps$|O!puD?9Gzm zv5%%)86;`LXm#4A9g>M#N$@L=dN7V9Yc#B21H8Aj+)@gbr7#*Qi|A=-NN`${5oV&2 zp=wU4*R)Gppy)x{4CbnpV!Z85|75G=VOElpEI~`-N_BN7Mzqn`%5Vp-KlCY)ni2 zBYvjtig%xPxsxRQ0}3uhynt9XIr8X3X3Zg@M3yb-IQpbdKHR(Iu2+X1e6IJOKKNew zu$z9e-N~HQ)i#ms##>HpDPP3WAnpl!UZ>YWxuXdm_qWOxbdTIgAkbw)04$H*WXjlb5=NN8OXRe&+ zs!3>xBVbhcydrDPE4K4K576TPR3A#NAA-ugfyM{2<|LRl0nRT1$*Pebu2C(PDb&$h zEqSU!S{aWB6_@JZrTSou!1+XVGRqV?)zzZBY|)890dPUw|EaHy2?PMw0rmlss^g<7c;f8vE)^~J}6OR4- zop-!fh|vfWO=~Bzy1`2)2w;Xq{J4SbKk9>*9Ut~*mQ^n0t2b1wKL);Fa(O3XMke7{ zOm!f1ohP`DzitV_s#SC+1B}Y#mNK4{d5;n_MnOfTuErwI4#+sMTv5GBGNC%L5uqcr zv@0A&u!9Qb`(Q$3m{8v_CL=r2!c@_xO(sQkCXTM^5c8B&#s*~=zTmn5fct2W$XBGS zR4FQ>BvDqQ#M&Cs9BMlPn;Q$6I{{acme`^e%G^~AP?It0l}Jf2Q8v?6c1M`b0)7#C z>d+w!p^L2mU54`RQM**7X+{XEYP_S%sk;8k`%Wbx2tdN4mJ5WbAb>z7;~v6K5KX|m zK&0aK(zeCVZhQ9Cq1P=4Qfy9{45Z=>weWRM%TSFg`~#>;$q;^{wsmMwc!l|g9rl?i z)5t&{OmXpdAZP(kE$ajq-hm8k8KrV}uwl%-uDOHm+(UNmB922wOEBz%;kc>$N@irx zqOvWpO}2>YqsL+dhJ_v}<;go%&ENR!3EQ^a+>o;HE-MI{Y8y}`A!0zDhURQ|+0Ah| zD511cc1&IXA4rj0L3bU{Z;J_qa9MQ#N7jXvR7hySPR|$ugQ2Y@(!@CpYjzg&5-`f*XXPgZrg>zRN3m-wu(6G}4JFYAYZJL~ zrfFDA!w|G-7*}>PN;Od%Vl%8>^*l&(+aQWf>_{1^NG%_8K%}8nT}jLg)JRE0TB>DP z(*P0*#S0Yb?HDG53^w2%lJyK_Tm;ixKPu_9dA13f12RBVs$+6O}?(`bvY7FlTV&>G<9)Qw;V7 zOLH-3Q5&xb*On>h|DbWz*u>+|^+v;6)wKMu#9ieV0HHVJNB-TqU)`3-lqE1+dzr84pR>P)Gh<~0i*XXCB>FycY+K{@6rG!o9g#6Dep2%! z293sYw9-mI?MOXo#ba282kz<6E`?4hu4$vJsCbRX zP1GopC9!ImT9GLNb>)TyrM=ot%h^Ot?*qGwSc-(GB`I@Wtag1Fy~GF+I9mqxVY($Pl3}qHkzT6%4gGLPS|)k*LQ6QNL5x>%4C2w4<7uNXdg2 zUDmka5mHJ%t4yc2ZzFk^Bn`4>2U)m~Y?m3e2MIG$i0~9Naa|e;&JB3sFf!u{aqE$< z3*uR+-ecpn=#iyMX8-Mh_1V#1LH<`cy`sc(+>v8W9(9}?+z4lq)2!Aki%-<2;xvlH z$v+G|U1w#{&*=N8>cs&?XTs43bryUme`E|CXibKZOInqtG~?9`v5E-+YM)yK%0FM} zB8Q=v?DU3cjJROnnh1kpoxCEPm!lgdIGfT)`&WGt!T}hTUySZWMFV6(bZ0S|!m)}C zA5}dtwZeI1U0roa0lfe;w8%KUT%Xf2&J?o)7KyVWz!$eG6JQPu6x8u;jjV(e#2^m|WBFQhRK%8Z*Dxd~IoO49O%LH7$ek&jicW;d%N8aGT!*o+sb}%>0K~FO zCR(P`F?H%Z+kq0d96z9J88u8~y_!gn(Hy*&p?!G-fFlKx>NArc z1XzMjeDbndjR7_p!I-^CmQMNDEJ1A#24o*_J1m?8n%H{eXr+S=@Kwg(G#XDJ4xU7| zd7(acRcAb`oc9Q1gQo&=gNVldbi8g!;3Njhm_+fgua_Vos*cYTuI^w8I|TvE?<#iaTH^u1_ODHrzfG!daGCrgl)$*D~~c zQkP!T+(wj1vH;aQ=p>6;37ily)}c=pEF$NeNAA9p3=NQYnlP)ZcvHb)D5Pm3NxHj< ztdr**LgYr}seu=s$#M|`9T^YyfRj}#j(g&XWkvrn(-h-6&;}wD)Pj)lO-;2ui&}^> ze+&4DalgUFA-X_nVM3?}pR5|4v}7*7S_Y*Hj8El7HW6!sbPjyJKxj0M+NW?2P!$m? z_me4$dOR3O*t~=TL7p`Vha5mDh7R2bJ4WE55Y@;@g6#L$N|iBUInJpTi{iTH zS6Pl+BPbJ56%>pz2vtxaTF$R{MLlVJ-9#hyV9k_{RnaP{c4z_Y zMXFQ;@Ksjy)K$FFahaU1^aL|)mdlc7Ufr~%QRNOHbyUruMC4(D z*WOfEa&@zK5XR~omZnlb6oqgKiK4Ngf0nXAg}|0etiG9q33Ac~vUfLm;&ITES0_Rb2`W~&z82l8e6o4hyqxmA=X7r`iN~q)t$|e88b=8%rjqm;|Urmyi=v$ zrMhX1fvQrpQJbWyDI_A&&07@OIUroe-}juXf=sA#d==^faX&1f9W+4Y4Be-}qCeWK zS%eJGT_Oc?QpK);>mE0KKrW$K0lLma-6d@URp!c80pBCZe^}5eXkdU8gh5n*8%UE> zQ+Y#qXDHiiib`rB!b{5Dxo|7AS0|57?oc6P5s)Bgg^h)yUyX2P3SwPtk5sXciZ%l+ zEQl?#iCT=Z;G|v<_;^}V^jw!EbqR?<(6`bVd#LbZl!+=lEIp8>B@eZ78>>mXgc@){ z=01iIBWf^xI$2`n<*i!Li7@o)8Vl6V@7xKBTsHWj;29n>T^EKsyaw6f8=8bm|Gx zL4?#bHZFE-C`Uby;3!(7O=-opkreVI(?J$5AnncMrklxdjwI`qu_9qwlNRR!rmmSy zBnryQHFr+zx#yo~8#-Jj;i?puVT>>`2zB{)OC_MVFIxD{*WUOpa*srL`_(Nh%EGF& z7Yl723cT!Kt{Q?=W#~1uyT7lurHoI;;j_l0pQ|He+!0?>oMSc&#Vqi$LLZj|EOZ;Y z??C4Ofk1x0=4D-5&9q|*4X@LVuqKxT_6g*O2=oPJGu(DKRSi5HVZ5SnKI%AEQsALV zq4mMQsu!^W0ILa*?s#E`DXd8DL(rLsKvB3Ll@OJIQ$iW7M29d8jb$hczrH$S%d`PYNC`H8s;NZylI zE5OnOjh`R`H>u&%psetr4lRyCi?H`{m$6w5b#3wm7E2_bBlY#w3{}W=Eo`n2kC04; ztUa8(@-lgD6LFGC+Kr%a1QESC1TP25PfPb4Wib<(Ss?=*o!>(>;?M_?>Ulv!JyZh4 zU~vLz9<+J!1~Se9?KfGT_Kxe`*I=#6*|j zJi=WO%P^A$w}1|BlqfH9;R#YzkWH{W=zeAuWqbPS#wVK~+Q+7PVB72a7VmV$P~M)| zG%Wy&18pOQ(<7*Aut~^ih1`I{BP#SwBEs`{!kO9F2=Uq518=mUUf)E9Hw`v-Q(voO z5)$kO9)?a|JfT=nME3=l?s&=XSSC@Xm;l5LNp9Gk(w6Mn_hk3Jls#jE6HmosgcqT| zC1Y5=SD8rrA!(mV=FdN8Nz0jT=dbvMVZGoRH6s69Ufq9KLcSHq+51jyO(vG4^K|Z0#5>TXrlmK2vC6BCT&{0|&Mxt+lO&R#Z z8w$cLY?H~C?uQ1~W8B)w+yVDO=_IYrF-ci1wH2yI zR;WIOd8Kt&(co9&n?``Z3Rzmn=$Zx&kM0DCbX=n-au8Gjg@;hY8#=I(~QN5!5o~)h%%$s#AAX zb?|Dgm0GD33vLbQkHQ~|MU@trhUzO&1r-%lT|0dhnR4G$dL$a58(2bEf<)}CS{bIQ z1Z#iue!9Ow;sobHba`Yzg>pkq$NCC=n>Ic|sZYi+oK%_wJ2qA&zyUTf$T&Et$qUX% zy0vAwq2OX{AEDE<3JjjEic7>0fFVOJ9V6S{fOfPxcxCczVqmM>RozvCR-n3aBk){# zxzeW5m`>O2+ST7!KTzLDN_pR8GvzrfllCA~mf7&gIfo?MT2_n{?z7Ff8k-qW(>=NX zTtV@eWtwj7xR%vI8mnm#Y?5fMCLfCGCiW!RFy#~8ETNei2XT^D(;S7GCr5A;Udgd4 zFNakDON|h_wyISE>yoQc6R!e?3(e0|0^!J-;T4buD_=_85Y)^EIIm$DvXb77>{$QnR4S8VLJmfP8|{DHd2DxFPd-<=I1(`UA&v z3B(IL9=L%SmVG}V|19Ss)jZO-(DAHswfvpG4%i_~yLK_G~L>fp-V7jrKcgZ6U zLAq-rDoeg8lL6Yt5x!~J(Y_H$Fo1d|MbeNq|?cxm-GLe$zmUaFc{2u`#tivie^tEnzZSP2a_QeYi8%zcMI}J#OAA-SuqV1A)HPwQ#Q%%6=OK3`p74hh6m0IWVY-E zZqw5FL1@by2NPeN2dNaqjFu3>TGcSg(AMAR+-w+A(;0+c2ZKz62yz45g@s%qrh8q0 zxM*o4E(e<)&=KH>m&9pv=)v$Qi~)a;A>1m!9u=bllV zh;gk8QOUaGN(xyyi`M@MvD2htSfPp#Aj$D*$_Us{PyG!{%0cxEf-J0H0e096&ixzou==Q~*QsB2+kDrg+b&ImqaE0`b@*oJLnOx~@XQY-++#b+dWx z9x9?m2HJo)oq3bcWs_h#`Q*?`9axpqtD@ayigB%PD)(ATp@vw6LymMEgIOA4BUBTb z3au$ot_`VHVN=L|iZV`|>vavT&gIlpRn?(TB|1(xqW6x_`)J8CCTf!op~)N6CsFwv zQJq9o1VoR~hIgb2DJ7!fT8*lZOph|O>dG*!N6Tvz&Tyb@M0hbFYW87xgUZ;RMkh7{ zJ5q2Su%J^AY3NknSa$Fb0UQi7I(Day1UMBE2;h*W725g1l4Zwaz);YzQEYxDwA-0( zV?jO)h%Yk$3phU=m;Km@Qh>?gA%e0{rBax^k5q!*fJ8p1Nm2T1fbi1nEq|m8M-XM=V2DKTg0i!a2 z2VDhjGPK2kgG^pWuAn&q;J&oj4Xov8hRO7fg1i}x6+u3bmfMarVU->RZXLXOo1waI z!rrV539ILNICfN+DxnPhD(nQ#qc<6CGE8G!8Drxoc-0{X3AA6{Q7YXAgiiZ7X zQF>K|ZE@e8?s!wj{En3?+E1U_G-bfpyz#|d@ziQ?TBMC4Y%*A<=e=AiElWBXSz~~| z4B)QyW*UA_F-f`fK12BQcYd@`<5=;vut|o0?}Ai(42=$b}Gu zF5={982Y0_1yDfoz0S_v0pHj+*t>YyvPE-Nkv!SETaYAOwPtxNv3z7OyKhg@aZ+LE z0&tot4F=_*7zHrXXaXprk`5}*mJt7X0N2(40!e6;$CWx6rzRv(^3*ayCB+T13tY+q zC_*Ou69iUOYXN2B426WKOe~`fhgJy%R}BjHa{`NqXv+BH^*XDS>%%@^QZB^qOAW>mh;h*bs7mVBf?U%M9Mf8K@S%9Hcq-Q z^0XEz>rL5d|j<#c3J%gPn?O_vx-B}erolgp?ReC#r@1&tx5ZWN)YB@FB zmo;_}6o$z#X>8#A!bAoy#1m8KCCp7=RfQohfsJ|Hx?OKPcjD@WpIx;i#)+}+nC>&k zf4x8+f0-oHw8UxA%UK}}WW5_hPKOWW?%H*vZiwuCm2_tZyxk9lZ^ULFb6QIid1(s{ zeoeqa%W%ll*X`N8Yj7~r(md7m`iK}ZY>>o~3qO!YF^KR1c`gjxU0pAvnv&~|IJw?g zGP0f2dHzzn$Ff`UyPN_e4ISyG=J_UI8bVqYq0*4@F*PuLBrW1lQnX|qABxF{^`wSl zp}{PwsQ@TE;mcJYxS(4Org8{n1TJofIz|H8@i3P&Z5yVEU`-2TPL7CXgNQN64nZdC z5>+Qs)xwvQRt<5)n++?KyP#=YJSXAA^j20pm*u6?$je-iLE-J?$pK9V! zXiE?!m{@^=mV3)Ju;jP2y6M6jZe9x9{%WaS5R{E(({{f&ukzNm^PS`7u8F#g8u zxCi%sCl%&bD_Su-(07oPit&PLrY)uQMU^|YiRRY<9>kCq=1RqP9se&MJ8R7!e)F^E z|9tBYUfJ0(qkhHQ_Vve}(sUH*+)7^9vN6%pYw(=w;p7JETWDN0ljfNu%#tHdCS+OD zx#ZpCNpkOlUar*+FnQLMltE%~l1dw$J%jb>##DTHuDCJeBZ|kXKtR49*cNM_*}iS> zE4hKek?l0?khP1*nnhMRHJ!-ZzmvSYb>xv}cDaSU@nl`Lpi^iuZlg4-a}`ynnc$rS zYHsw+ic%$PqyTO@9fR2=!|?<6eLuvk+Oi$Q9Lmy2SQa%vO&_vS1Oo!!MkpWh5PM5Z zaph~;kNY``%81yqjl{vsBt+Fb5#I&i3!(E7DhqXPB3uGy!=cJ}^>$@ctjZ^u|5lHn zHGsevyOb68m%bek7lqEGRZI^uaom<8;z0U^wW_B3e*s2KhchbJ=>+54gA-AkRCa+x z4&)l^1_~l3a>a3St#tK;ns6BcB!B>NVt{wfE;_v8-#&an?t%+1{pkBQzx3SP_g%5& z^~Rl}v*%B365;AMdbS4sYb-ufP!Hz1CUNs*`V^8%ki=9%+6fsTq)BGtM5OI(pk`Uo z;tL^iT3e4yZz}{Yu}W4 zr!AaK0&(HSZ5u<@OH9bQWQp65BuhI;cPD8Uq$!RpgMbX?Nl%INXF;}(M|fUD@&UNA zeae*GveJ&Vn?{T0cg0wd`xLB|Ln|IO)bo~wnYwe{efULZ&YaZ(^kAceA_xKTUEVeP z%#OZIwq01-lKfNP4G3Poxq2X=i8s{&9BuiQj5eFNVOT7>G8!%0))aH3)sZSbP{0QER1p@+>J0Ktlw>g#nMWh>lzkP!r=l9P0FbCqNt08Q7ev=72y+o~9 zN#5g_N4+gfv%jyXJsAAen`|?Y^eBx`KnCiw1Hx05LkLZV@=>{aGxUY9*swpiI~bkT zy7-O$&Ze2O96Gfw#TIr9GiP90V`+0&%rDCG@U&6mer8zeI;L&1^EL8HKWR#kE96~U z2En?e8z?kN$T^}sLftL@qE{mA^_k*8(JYa+W-{!~GrU5Jl}=LOQKzYnEL%#NP9X9N z7c~A zgN6+3OYx`%&bnHu2yQVzut61*X1RL=i_@_!(*hk9*Yl82j>j$Ky3>lnGEvxQc~4G5 zJ&!?sR2Oy=y8RG8Ucm+RFgMEYaHq>!Q#hgS6D;W!uv28=rf{5icCQYUPF#X1~$N zx(459Z(H)rtE4bIjl*=dBoB2N#KSpq=R@G5WaY@0U+AAXC1gd>E!xQxqA~y$dA}+3 zOv5KBhn%>&t==LgC)rG#c=37$EJZg>ItR)07SiHi#Bw}%izL@SS}bn$!`-7^SAp~t z#fZh3Z9ArIM5=)kT+3=j4rHh@=5r-q1{#H-7kIuWuLnBKftoK!=A(E&(nXD^)d==C zGQF3VP)#@~kly4G9hBTKWhG_FF27w2BkK(T;$X_xE8rR^1L?8}(*d0zQy3}&l@0gP z>KhMg`V$;a;_X`BhG~or4W;Yr9Vb>SmgGO{lIHGxeUCr>#JaU>TUuM?W<;wcJT-HO zX41*$o_(>exBuAVj{^-^5}68?t+oj7?H?Q-8c_vlLt}j+mI%0#ZZ<57J+<+LWGX## z)=aPh#{z`WvJ8a~g3y0-;EK2Fn0;$gq=R^2&@DAoV-cp6%H$7E3)Qk?rVa3y01P5~ z^S#^HzNYxBj!b&#{AroC*v8klJ+^skLvx~|wYjOj{e^9v!+fY=q_44Ys=Sd_j7*=6 zU`dw@W}CbEp=;ILM6Bp^Q>_kwmxd5jjW$_1jdawLo?UQCwlo67iuxoCzI8Hyd+xlm z@1*4mnqq}qVYlyhyFqXN$hMr{=hL9*^MR3}q1-@wU7gRoyqC2tYqC3GR$q@0Yg*6q zloms%!F?u}QiTDqD}<@(evsKxqE(7vimQr4O(uoOrczd*u8itJF%h$rSBr@P1YDVJ zP%}V?K-5-Yc=U4RVW)iUTO*#C{2F`WdFA?H}Cyv%fy@$ggj|RS>5+ z#=iH1|MxEs{O!DpE|$OCBv07LHoJ4kZEbMOs;)wAWUz0rSC&q7ajl6o;)z@ic7gVc z{p;WU_H&>6(zIE#L2}Ob{`KGf?W|LdFTVm;kgxvx7uOzh!quPo6wDLxqi3{OpNTus zOY9!XqaW8l<{TCW8LIREVwL_kGl&S+p8F&44iI5MCg~K6lT{Uw!_y=L2tb zeX2B)?JAWD`BI_amkMEN)b(?DtLV#Y*KMzB8}W+WxxDQdf>tT1(1}xM2sZg3&sVcd zkTOHSEesgt69#^0LTExu2}IAqY!0hi?FqoKyJG2ZytM-bOZJ`M0k4`<>OjoxU#VINNu@=27@EnVzy`*Mkwo)eBSXG&z43< z2B~Y>G@bXeB4hgP%};K*H~Y%V4e5AGa(4ef>&u-+wlLH?+&7SQ+NVt6T&sguI={H& zp=V|yh>~c<9IXTtlC}miBTY8mx4T$O9r^CYd>857NtPW(_I8pTyNR8APQ(XTy0~-b zCDGqkD(2nLas#Un^8S&L(Sqj%wi}xAEPJDO*drw$x>8!~sY+6tj|*T%yg(oj&{Pt_ zBI>#Th8t)PAUYE>O(p&Um#fMg1!cfdG)i~L04>N>Z#v-0s9JYWfLm%*^>qxQLG!Y} z=7vefEF&?l^C}KH8LN>n6>qkJheqAyix+G-<>Z@hxmgDAU3c6WOQtWn_&t}t_r2f! z-uFIx)u%I=^hM{N|F2*A+_Du*e|YVGKJoN(U;XNrKmXaQ<}X;>)3yE4M;{sLKIezm z{P0`f{nq!t_nj+0e$_2ET;rMG*XKC#mX?;ZBaiU3!Y1By-g@gr7he1y-}%n8)|P9p`41Eh9fyYbn5}7;QC?EOdNyT z=4c>FDLdUhN)AnlwbPxzOWWM?OMz?2BU~_tnp4}RnAt%x*hdVf>U~memBMI+JD@Pz zj3M!FggmpoD2m?tHI1d+WXsk!RvtMwpk$!;<+hoN?|XFgp2xEBOeSzF;icq(%^52R zp7p{kXL;dq+bOyE;lbfpI+I8xSr{NTa^eq@R|!{uTm_1StLYJC%3rdg8LqSrZ393{ zJPa9%gyHXL+#FIlcr+J;CsT+|1)l0W* z=uh~8Uy+@tl87YLJ+8lVwMN+D3(mjb6QB9K{Nne&``t0e9ec>^*^Xt(x82&>a^)vK zdB#b{{^`E^Ha-1xeI|MN6_;On(Yv30{K4m*fBw+=^Nu@?J7Sd@asD6El;UsSejyHUB0PRU z!zyQB0fpdTbNSw3ZreO=FwTJ&2v|Ddk+9@rCuVPGIB};{o=WnH?gMxo zvp^ulD4FJKUhtX||2NlOCUaB8eNc^CC7!Q2JPMklB~9R3yttJliajT+pSyFoL<*bc zE^X=V-SW&+x3{%475%n7qw`4Sd_Vr!zLD*Wrv!IBUd*{}NoIP?Ayx(=#m!P9upsBtppa*yV;PR6JhYG!gQFoC;-KUJoE<`IqX_UAN=u2cI2^me4Ft|v z336k&R_NExLNM>83ah24xu{DFziXPdZK0aBZz^F^Y&L>6AoA$L%6Nu~1J1f8fd54q zhkTxa65nvzDf6$p{^M7Ern{%_OJDhBZgd0;LxM0}pV1lsazU6@BI!8T;t#xHJT5C& zxd}3v?liZz=W_XXo_+omAN{nvYK0=yPNTWOm8;+J&98sARLCZivQ~0G{NaB->4dY^ z9Q$MRX<4Rfd&d*;NLEh}@!t}_Z>dxfZ*_+JcOJsEubTpd zJqTo7>YLQJV%DBL+1Glv755BVctSjp zY|bRpH{=UiuDzn$U+Lk(*UC1<3(0ViIMaw7c09XtZ<-d;$=H^SFKv42(fazKg4O)o zCVxkMc6v%Sp2#~f8KL>WFAWS8hWCsLS?7W;bwJ^eb15y!OxF}FKt3}n!|O>6X0kyv zw5smDvPt0siZ)~cj0K|0K$TvOJX!e%T)Cx%^6aOcAo9GGwY1E}ivi^CC7+i(-vv9| z5F1}g@CA{UTC5#p!wv9tRsKM5>6n0`+hQbP8y57x{Ln9oFfdILw~e@M#T|Jh%O{Y# zExuunpW*&S6cb8DRkm}vA^E<{_66n?uIpKZy!XBD`{6a;ZER^>bjZ~Hp@FX6Uf1`! zy7p$XIr*49Ck8ye%N zP)WMG`--l&eBrdUs}?R<(2>s-HoyGx8K<8TxTVdTo_*o@7k2I5SKrjKY}v|hfAi|c zo_gk}6E?_|mB=K%eDyaTc=++ZKKR55C!QS1=>7llW54hfT)TP&R}Zw6j5TF47YzWx zp@cO3o&C0JPcu?!Vq_?3V62g|Ovuv0kl#sDmf}V#Fp}IzGBZVKn#fO92S24LLefOE zQ{I-#y%+@97#a&&NJ1vsI}*r-0@s}kfovWk44RvaxbmE-C;e7(ho8Uy)!y5m?%W=> zzf_!g=PQjbW~YqUWYCKZ=7&dexq<9J&v56!$f(avY9_%KUCHcGx!Zt;E!Wf@G1=~B z#M)=Len4`$>2u~>e9pUI7YWoHh?YOpeAYzASP}%-g$B`h8J03Q!8%gFX%uqMObpNk zL4J*9HVAbCP#1D>Xr*LerlF9Bx0=%fAx6kHED#l`| zl`EE~)2YQvmQHJL@jSkC<;u1x)8@~cJAY0`z7#H)zi|4D>FK(L5C7Ap`}TER_rq&n z-}1(BC!R2GZb#AeZO07VaO#Zd3zx4d6oQgZXU>?KOk{5U#n0oZ^o9+m^$(3KT)b%6 zij^0hf8NGtp8Wki_pVyI{xhGr{Lm%K?)vR*k3RPJrT={S#pjd%X=Zc~ zhj7fchDQsx-F?sCzV28$y=ckYp19o~7-A$x-GW?zd6&;<^3!Z2@K8XTp`-|OS%GZ^ z*gghmKeQ%-;~16bxDtRsVl&uTg(Pbyk2bBDatG#^Ax9onni@y31ujdV{y`(1An7E@ zmV$!I@^1X)?c2LYwsI#%l2*xxdq&3PZGjcH6V0C6?Yo6h&9}+LKPY=a)CzCdn0jtfbONyx)AkVq*7OzPN%1WSXQ! zWfd1^q<^&3n2E_(Rw6{63w=3x)q}~9B>!-j#eTw+zSXn$Kwm;#D!yZH|Jm>V=dDj| zN==<|?j>iw)Rfvoz{P+)~EcUG6BKKJQ^T5hE}e#Pzhqkj@JwMmIZSfh(lg_m1GBq z3xWv`#H}7GMogn9OLX6#*Ee#KjGwxctOjo}$slzjCCt}>D1=>rzzYWaKqkBLC`p->O%L*69>Rndp~zv)JrKGV4ImFCg>5JS zZn@fV6wEo!g%#3Lx$Bj!G%7d5QfNd$B4#(!K4YMb3|w5f`Xl^e7#c#vOdAl{2-6Nj zsBiRHt&|7GXhdTtj46q8URL-KDl(N?RVc~`4AjS>%IrQ=MLU`aMlu_wDf5di9~gs{ z8JERXch-d=lkWjG%P{*!WzitA=m%)qPIuN*^kUmIWoF+!>ROhSD*^gU31rDyb|C9Q z{>PxGmG9Q~f}U(i<`r2#PzWN;PUK<109Bt+@MH;lN1z!dcekAHld|*J-y5kDvn9me zH_xd8Y>KxOzO>2^R~*pqKqLkp905+cU}a>Llapm`!jLDIXAj7|wk~a&!zglxCL}^h z8_4Bud!e^rb$I;Q9nbuwfAiyoSUf>kAk?~mv5id$SY)yAuf+am-%C;p4?$G)Gcgc^ z3DaGL#GWy|ZtEMbyzcf`(Dg77_bO4vg0{v9uzotSE!Phu346a=dJ>Kicuvf5VWg-lFyWA{e!rNpg?j^%V+&uMM!BY~bheMK5sEj3&YA3{Hk&LU%EqlglAjET+=)7tXgjW(99-d%BqIH)yVy zlL@2+iq(*fD;f5n;vJ(6b*n|o%Kc^}U|}|)Gfb-dbC?lHzl{Obz+^~hvj)K`R^b|| z7K!>E^a4OaB1En)m$sqW&&rZcpc+w#%|W9|G?*%Pgfsw9h zQ>VIlr%zUBLwO46FDs*NqtL3|!fI3%6pGoX2*u)@7v>hG1)^@2Nvl6ii&9yb%7o9< zwq4o}v-;Dh>U~kVA5I@0Df+X_st2yKFkCJ_i5m(Rx>76@Cdcg};KB_<*9+Z}ECaZQ zKJuvQ#6%omPpW`E^`VCMz0fJMWz4zXI*LDB-pVOvHoils( zlMg?5&go|k_KsX|-g#46TVWJXbpP_eqa(w)=7zWr@<`;d$2Pw7(pI^H@7l5B&-dTo zn6&F``p`pA2SDt}jR;ZgKAobo@RNFJUSR;GIAsE7?Gbo^7Z7W zCyOdm#xQ@`W_$3Y%lo*340A~EO(cA^q25f@8K#}LZ5M7JPM5*|1kjuEo~H}>MlZ-% zR@$TqRKRmbhC8RtY+JE>X(mmk&upGPV=A)akp_qQ1EOL;D2)AXcjlO+tV(M}OnQAu z1>ty*(7ei|QNA}GggWKcq?%)0SFOU57{{Q&ax97~A|MbSE{_}^|&z&)I?(Dhpt$p&7SMJ-_nHwEF?zDG( z>dMQ9a*^qoP&GUsM~9_vH<0*${)Ygjd?ChCXRhPjqa#DZjF(IilwNq*AI$X)w&Z*# z9uJCsP;S9!bdbdil6?K)tk1JejY%i&h|rBHP+HcCFbvoBpO0JHvShJMlL0JTd5$Gb zGo>6A>oSY#GwnfGGL4wlmIJLhaEP1Mc0@G$6m$i zbOJ)Jjz|zJ2gOXH;GBY4%6?DzKvoZfIIXSRjJG>6RJT!#n?K<{r?$7eUBZmZqB=f17Ox-8mqOoPF!#*W%P-v9 zxuxI^3hJ7S!vgmG?#@0crmk7B)b~c7c=m^>l+0{NLt{cFh`V?0w4HP!InQ%nVJ6g% zAc{X$cwB3olrhkB9Qw`VyxNHi>Cb~FXJSca?{gpAr%pwf8=tR><56r zYieq~{g*%Ay!mCpp=%}cCRrKGpTFpgv(J?eS-*Z=XHQ>hO3OJHTrB^&dgZD={^_Bv z-agy5_U_*I|FQQSfKgRx+qajgnVIy25PHXg1#DOVQ7kKpt0;C|UB#|z2OHQ6>e@v_ zK?T>fSFBj+Ep$jidNP?zzy1F2Ip@w~LJ_d-_x<0-2*V_E=gz(7J@50j=W$E^CujUK z84FK5ZxTc<`u5=G|B_MedFUCAS_>!+_pJS zNlUySpqR~28Ph=W>zI+9Wtg0dwxcYS@krtWHq6jgDVBveNEJ)_6-r=%->;d#3YSaoVn z7&@5NPU|RpGN`b-8pd9~dRs%ofx{1+@{h^zz3;Gt?tc8KTd%rYRZ{}Xx3z{>tXOf% z=)=~nUsF~wKoZ2Ce_8-9sjl6YRFYn=x4yBdTeo7~BRx2Mie^wh{IsZh_wI>=zI`f~ z`LC(|!mgU}P@F(3TJwVUqxE&1*Qe9AZrNbf3L-@^8d??DTES8|mb0)33FAmyIov3? zNrGg|NQme(_&N>#s6&u7%ndYaNm!>$F~QX69%UX`ET*gmn{L+adJX)!tArOl$@CUY zZ2>DRF3I!ys8v<#8k@Gc-C{~p1-iFO97NgcO1pU#wLRWm+pT*bFW`5%H?)Vt0?&4} zgzacpGxfWQ5Tb6uo*Xwg$YpPwpV$IrnA9(W95C6S(#qz6fyzPrm z-@E>%J3MahqNPjEJ@34Q-!DAtob$A_B6;&3f8t4&2*$84jAiyaZQIMMg*;K9L`#*VhO7Ml(UB2S~R(Pq1%E;>ht(R3n8N5hKv zwoauBJciUs^}V+-?XM1o_ZqeSk12SzCe(@NoIT;pGgC@BnWl~%d-TU2e$3GJ{SQ6N zvrMF;{hYJU>_4#o6<1!@qbz^T+Nv?fjyhr7abu4^`j{h+ZfQ*n95hH2`I#@y`qx`; z!TlR^{P7IKrBVt_{}(pztqmh8HHM?|OM;q}05t6|bepzen~wAwW#_ikf)fV&WN9L} zLpz=q5A8UUBB)i6&8Vb0RR|X6hQRDSK3f!h0x#%#nv;aq)(zWgwv?0%EiT=!qI_5= zSjo_`VQ2ymP(9VBZ&{DE`Ae5Y1ve8j~z2+9OHXEl)b*RCuyoHIj++ zAJ-%K|F`|3lrkp<@(Q(-fjWdUvn!@yWEPyA8FVGZ4134pWLj#SM|@{*kCoM22b>h@l zzxC*QOL6!+dN+n;lZr|yI_dg`o7o;q!&*{RR1J9i$)|W;XpX0`8ZC4AOb{E3^02sXsS!zP-b=ol$!xR1nfs9SjvwcABQw zp9gn3kxFEe==RRe`M=h?w^!fM(ncLfmZd96OOG3jj-Iw0t{ckv%c12*Q!h-;eRC9A zaSK1uCLrqcU^#|En!q|q=}g~&VW-n6Raf0E50V5nQ0Jhonz+l71=ws+sjb_7+PLNC zpl5!M?uQ?F`1n{9y-Z2BbIh<)jz9l>_N@;;ojh{HjJ|#7#%8*%u9~(jS(aik1<~EG zhH2}DfrfLCjuRTiv%&u1#E^a$ts#awG{>U|I?Mgx)=Sgd<)i2wp85as3-BX+EP^iv*rr&PYM@yQRS^H!7?{o|kLF~S5ml;9|F^#RKh_}s zV{g272gv5v6MSm}5uox9?ACdQp!a2PM-dM%wF#9dMATrLYLF2Jjfs1KA=O zJ;D^NC?$tAJ4}euuvnnT^E~%^8f!+5Ju9NAVvSaT7YxJTP~Q~|h~6-C0XJJ)j`rnm z+TZ`1v;DvM#X4BL`1|b%&3f=J{((1rtPAF!@CFjrj#&Er)5cZ zxoCm4R3+ZjxGffK1@jgJwms4c5v#^6`S#ldNbiLUxgi=pYt1elJKQc)EUz?x(jp%rnQPF=MaS%#G z%h1s1fDUc}rFtwPBkFWIV0}y+;^Mk6?eJ-n#&$LXteyT{5+8d#o|fje>C>mzH8#q! z0J{T(n}BECqAc)yG!Y|m%wE|YOUDI@^ZMCvR4oc!anxZ`o0}U-N|RnsT|?uNNc*NO zH7lChnq3r?$T@AlL5t?=dM4>6$syD>io84ZY*OO=KYF%};*Xwah zTrv`dz0D7i0iuAj39kMV7AgII$aH_}VAKC}a6_;juIgFlH;;b7L#KQAue@Fjx?eCrv|>B%veR zq1$Oj(uNH3`+{{W-@ba)JEp!_*IIQm;q|(^l@7L4ty@J!ad~-bG`eER57BtL$KSJi zX=P>43V+DGdE@F;>z5XmboaUn&CA{x*}Pe<#!ZUlR9cBPi!nV=^QG zx2ln;BQgzuX>e#eXJ6|w`H>r@p+P{(;h=&a#NzQ#DD?Bl<&)tKPh2#qw39 zC1p3?bmRQD=ZT^$dtBFCdFA+1Pq_J(e|)>}YRDsbG7KmOqLyYlk9*Ia%1;UhFrMFPz^HLw zH`A%O5p7JgG=v))BH=K_v9cuTnhp?MfUA>=Cv;7VcZdS=%kefn)xm2fEzo8o;^7q} zZ@?P}V!j)D&pqdVjh)^Due+pv%z=(& zBA-oKo>;fby?ptqaC6IFPCjMDiWS{^_LzM6m2>C34j!w%p>g2gL04Tqxv8O9hTb4^=aAP{o*=u7K@#mI=q$KHu5G`;r?8~@|dvA?QH^2^7>+)P&1e678S z8rZ$wENu3VEdJ4ZeMd?0)^><9@IY;6m5#=wug(Lj>mI@4QV5lyQp!CbjV(gJU06sN zS3pT3=Dr6Wyzs&c9)I-l58r+N^Dh?&k|4`sQ+?fs@4b89^yxqT`19IzoBH+{{PBmM zZmHe!?RP(JShu+?94;>Ho=9nt_81)cs;efqN5gkbT^CCyQ%YMb9J~A8X%i=&`L~NN zKKU=F`18E=HFekj_mS%$L=EnHXAUcZr1J7h}hR_LWHx1uQiSOQK{kVTf`Y>N&By_x|w zYig=eTN}M5ZtS{u7`O?e>9(;&0wM!>Y z{_*>t)>f@K|Dp@dI_ore`y-A#dfmn~@BI6nvnE|IX7o6ZD|FLMH$3y)(-Y4cf67Ux zRaaM!8GG0rw@oGC>#sCmSW~*DHg4L`R8yrTTX;&%6B$)iV0B5Nkna`q+yce&a9ecU z4Ebf%Fq6p?ON)hh63RmR;LGjd>{L7n_Dm~Lozhb&)tz7IDX7p)ir%A3|GUSLsC70N z^vVxxpU!W4Y5pauX%Z^54 z9LN1Rc!V_8|Br$^j+h38r2%oG3fGAk>_T;NKZ#6V#=&MM-LcTCgY{@aB}j_IWF6pX zLg&M}J?@sa<`-Ug@vxDH|FmTB@B@Z_^Tjuop;{3>o;s@sHWN(+6h%_szw|-94Dm;eBR*KUw-$*au3%dUyzdNBA*I#pWeSIC=&!I#2 zyYZ%*170-ULc~IwqDh|Py>3Ck|BUJAMuVx}c;l_>*RFxH>{d~6+thpV@_fkt@$a-H zH8_;dBe58tB`GS}o&Z-NiinGF`t<2be)n_KrKJO$&HLaJskOe%tD$OY#egrc9k$(W5dRPySki+%2hHm+Q>_o*GCy zbqRYt#o?9Zt<8~>FZ}!J#Y;V9WoI8Zdh^d;H#atklFPQ?n(K%&4d`|PMK0$SL>2J#Ma@zNFqvh$)GO~jzt`phREf`n1*`n z{O}`+DlMz1st-q~Bu$mLC~uOA_!vHAB`iv@P(cW_f&@I?a020K34%$Hil@neyMsw( z1XFUq;J`8bB#(C`5=~mUWh6TjK$&~A-cfL1MO#}MH?Pr>;dnAq=yUZbF9^4`!F3QM zk@RaINP{smi?n@M!%_tXqH{~t4c?G6&C-ny4#_d=CT$C%1P3k&`Zb$LCmRF)km<~e zSUI-)N3?Hs=>~O4Zn#LN9DiIxbIZ%G%#KGQlO~-7wlw|Tdp2#UUhw%R-Me)=Y25Km z;aE*u>(V8QBkhs1&OOh=QD;m%>+7$7m^*i_C|c)Cn%EqUzB6}LYkOqI%deDoE1xjo z)L25PudUy-VeOiA8%`d7Mrmm<8BGQx?%C&O&Yt!1`|rQ=^kWZQckR^>Q~l${>(7{U zZfU;vrmL?Rame8dzyEU13(tvi;EpMG3LbIVy>~BOwBqf5{p+5)ZvS!dvR*wZcbl)- z6;!5oOYqw{zT*f_{ff&^coY91_e*DcoN?1*hK3Lol4zT;ZOr73KPTqKW3xdJ<}|gk zD~kAA2KRWRQ%Ye`;YAl+(%96bh=Iq8QK(x0W_o zH1n&`l$KK4c|oSBKni>!qq*EJ%x`C>vX`0~}iG_;-(I95QGJlUWv%Tk0A?(UNk(xhmUe(%->$X$}vG-iHZoQ#v zcil1d>F1t3YtmVd+<#v}d1T)q`y77gA;+F@TvKiB&x;mcH+k~H?|=UIi_iDz*Arf{ zY(-UVeQVXGtrwg#Y0%&y@4fT(>Z*0;o^$STV~!em*kOrS?5+9l%zO78uiG6{w8M@Z z`O`@!mKWt8ebkW~s^9$N!;k!-;0;$^3dfl<8&K2BcieDgxz~T+Lr>UP;%e23E1i_*q`m;rZPi!PhLDA7jL{Z^W z&?e_9=^4Pgq>)uN`dz&19wxA>s#f>y-yf_unzqx)cyYcDf}kzcTlODz;EabK>es9C zxo4ld{<>@Of`M5xXR7JM(IZDa|HAVF2k%=}*)3+Nu}Gpc6dKsO;hE z>rR_6p<8L0*PZv!!;j?$eFKIJU9oK0n2{q|<7&@dJ!FRd?5oeNz2VmP-(RqG(+U7p zDq1B}UN8@_1mGFNL?Xr^*(|EAzP`3KGV17&XFqWF&3D{)@uUgu$=%5$A>3&1^b#<; z6h*OruS`E)>eg?B%D=ETBPlw=(GUTPNTpKgM8c9ROrv31R%aCE#K9(k&xnQ=OX%VV z*}^ipIAU&B!n0@1N~QnHK&Bf<+E3^$; zlH850(W1gY&$6Dnsw7p#?e*pt6vCy9r&5wEr909|CC$UWvpu&FMFme(l|~JnYO(b?a8St>$$IR{S#Umwjp7PNrkNJa@lA`@&DV zS9B9uKHS!N(1;Omv3c23R9GOpU5!l*9g&XS#RXCbnOQ8UMp|2k4LblHm*nRc1oP{+ z)$Y5`zM|}lg`11>gM`-@b}q2q4?p<;0NYD1zq$W@eOE5~Dy^iklr$Ajrgn9w5$V7C!N;AO@ZIl+=8DWR4o zl&vfyx&@b4_HpnItc^7Y=(J%(Q>Lo9EK7iMMw51{W#NW8pG&kfEv7=yDphT+FA4@=18i%JR8&?p zw{)zR>kA44C8cGdU_jS&&454`O?JSwj>nUtAj8fGX6*6!7>;kKua8EX1h-t#f4}1X zhagosOQ$KO3z4d$u=smrp?6}#aHkTMecHr{cil7XloL*R{f&9BosS!L{OGY`3k!-r zdhfj{H(&eNr=LnLSHHdkZn*XKHJj?6N_Sqci=-0pB_g^jmv_k1tOH+%E@o+HU`Qo!rPd$13b1%&rJNnS} zSn|+AkG$*Nhd=!MYXH@YmoK~Srd#0G)&rog*;=)H)v*1C?0>+B*WY{t4EURGf9TVz z632HIOIy3MmR*3@U4rQUO{^d$R<1NvbxTb{x4whj<&`L`bP_r_d>V%7^Li+bjmP6u zXUp1ly)X`oU4|hsC(-BRPBF_bW>>`g0F22{<>(v?GLx(+YM$*16%;U-2M^yL_Q?EZWC!h3sYZNq{!`b&}466HYq# z>i8~^-?U*%)vA>oWpWm!syZ(SEXOytchohu9elu`{KC9~!je^M*0nY@_3TkuSXi7+ zCr#57BnePRJQn3y-seNHaX8$bUl@XT*Co3{`32z?-S01S7gwqbZ|EwW$rJvOJsUeZ zAJ|G0C4TQGUwn4S`4=8`#Nlvd`VSZ|?XD^JOuMh8wdvdoFI}-}#VfO4r?t3?q3*rs z&Z;$4=l|`J@{;`7vtK>;oU@NV`WTkuf`y@f{Ntv66{U-pt~l(NV<}CUa@UlB1NwjW z^#YU&<@f`J5BK|h2F^$?U%jShpS}yf`|gDoUmCj4kS88__`&<`z46-XAoRNV=37P% zKj7hqAAf7!Jg?7t{q@&RzkmAUGaj4p*E5Fhe^6Oj$&81lQ<u%$VLFjeHZ|x((Pl>Xm+q=5ll4}XbA-+iK38|f_IliO zVDJdQw?TPo)z%;^fM<0LdEyq zd$(pXr9t_nnJ>(Gapuf9^C({ES&|Q-EZ|!JxT`j9f!FWTzpsw4uH_S%A6Kp}Da`L) zTpUg+9Ls3%dfJpEDQ%dhuEVKINC4Sv@901Rh%A@q^#?psO?{)HTm34_Vu}`NZ-*=9 z^ZFv~5r$?;i$icfm#Aqz_@0&J*aM1S_*5Q` zdvjxW+_@KTSXIU4l%!BViL_J61cfSq_Rd@TcHCTSdne6e zP6{lOrSFt!`Xv{*!;=^$SUEdIu5oUEW$2xp55&NpJ?n*rV|(1(mi09o*RAo0yZ`_m ziC@ddRTBEUR~PL`==p^ptAZ2G7Rg5lMFIx*qEY19lJi{h^Sjqa%Sx5iASh zI*-?@8}{bvnqVM+po6N4l97tli1GjfD;@tSi)j14cKBFLv4ki}g9i42pS7j+kjxJ| z-~e85=lk6XR+udkjH9^8(uaHp?e=s$}W9HB;fyZ&lsZ;Je# ziljInHT1w?g?XV=IzcFqz3~f6aJlpF;cQFrod+g`P>rf7Z zdR71%E7@m+BzH4ZXFHh$A`obrUHnjI&}#2UVzb>D;wRkFuBVY~XV?Sr{D?fQ8`P4Y zzgH5izK};27*Rso7%jNUN(yu>rkFZ75Y{D!+mfktx~RC+B}ffTEz4F{wYEiy3kwGH z?w+4#x;-w$3q_+`U`JBjyrq8G@@4&cR1E6Z7b&<|D%-J5WnE&Z2T~Jp=1A;czr*kT zwe0rk9=zgJMb$JTxml2GhS?U6BcM1JLw z#Hg+cJRgvSsBVWNahhd9elO|z2%Dys(kw{~xutMY3*o0>M`%x`4NVIM{eA&8zDHC| zNhxq@#eN^WK~n_9Yy!{adt|s{8b!566NnPRp+xO;s9m_V=v+s(7rUWl+k1G)nO|EO zw!7N!ZVhzzF_59UUDA+>(k;stC6ZAZ_ZJeAKzwsN-&jLynu^dZP8cxO_G`n+jUKW# zNZY&W!Qa99Gx4XrXA6@M$J)E%IN#GXPrF>ZG+^+u#Jm+%_X>Q~>eX8|t@XGih=e79 zlMtTP73)JmRTKqYU?ou!Wic9! z*H&)@oH^>4(X5e9C6h@*bEO#*%$BR8-Fci8{MC$kzsV^$HAS|-D=l8R=Kc5Hmu1)K zr=QWIydar2X_l9H7dX9?YOq957z^5{nktJ@Di(iY)+^&Dj4ukhzxn>h;_f{H!Mp-l zT(x2AoH?`i-DkfEr<|xsVnco7o1cDh?s;b|Ub^!A_x^pr}u`I8{wshRF*;Jf48qE)WQ4w%rzqpmt}M90(TV`||~XD=YW6HPvw( z$MXWiGH#cvvR5~W6F5^dG_|9xg`zoLKx~2((j~+a1pkqVL7Fb`inHgvHSO-{qedMa z4zHa)?cSNMzIw{oQSig&xLV{DV~9zX0}q+ZXhWgD( z2uAGcfh`M3q~&>qhWh69%NEscS*IsslE^9+t?QP|V&+cG$aBk*#4BlqXK6)A=>{zb zE`Vt+w;K>YFjpK8Q7;U#|g=JtXI$SwzlT>a0eRVfG?JH%PyTpw#>4uZP=Qo z`+Rvk2YAx37@oCE4)?!UdtLke9li+d%7gb$@6)&c6OTLqkLSJjVK9&vQM7BXxvqX& zZO>kP9)J9y?-u?zckbLoJkcI*z3KKlj~c!oSmq&z9>((Gh~bB}woIangxb-*Dqw^WSdRybkco+}CFPwB)CY zFP?nH>3=ONDV=oo#H5C9b3=r3>GPeh6o&3}bQaaM z%g){-B2n7WY3<@Rv2GjO9*&?)#DZZMI|igX4|o5VK?oZ0xw90@TFwN%mD96;tQWN^ zW(HL0J*tJ_=2$1a22J@aee2jlDwsOQAwImXLSo0l#7?9G|gYZlA2 zSr7{3fx>2AnJ*dTH89X-YDwLCB$NI?W2Q%jNa?W!deKU2yQarbdLe z1-7NBM%U6Ek+5l*N;=ii5oI_g==LTf?K-$`)rcokk}O&jtOpz5tB5&%Eo=7>`j04C zVsQ;>>aA0j{kU-K2`Ak$^{x}g9Y6Bm1O9gY*{vc9{IfUT zc6-mtvg@zB5?)eUv#p{>&pxHa*G|6N?eVA@THLo!nF{grS?8X2-3>QQn}!NMOP8(a z*1O*&=S>9bZI47h|K#((oII{(+t&T|8wNiuD=T-q-J5E*9Xoc+@PiN36?Bk>ZFTW@ zbmq%19e()X|C;w!MQJf^GqB8D*>YrHHu;7?527C&?C>l_q%=vBLN+j21Q2?+&Kv-5@ zZkR?(Yja0?yQ--0+wfnkBih*5oJb}NO=lTf;^|m48jB}9-aIf{)Gm&CMbH;b7*KM) zc06x3(~)myhO>Wl5Y_oEm`kZSnizk|iHldR7(8UivL#Cf^&jxBcRx_lDo0cIKk|em zFyXdVSTR>!bH*hIG+bg2r-nwvldaZaop; z^!ztxzWCydr)C8uo}oJng?NEjbmp5uZ8PW_GahI1rVb@9$u7&ZVOvAFVMO+4vDj9; z9vQcs8AyJWqJ18ZWtqBRNG>;x7>O8Okl@mBE>}@OA-p`ENT5U+&w&>bMA1}Jynt?` z0;>R_FIH7Gj*|oV`Fbiwa{`)euyj>Ri4-i6Ut)m3ixP2bGVrDVqR4zF-sG*F<~jDX ztYiyaF{m>&uH#BUk=-GQnkFwPp zH=K3GnfE>T;G{Drpn8DIwRYV)c#udWJ31nj73J_a7z&A~z)S@~!Q#TgBaS$tAmAA= zXyC?;8@etpq_+W`w8aEYdVlPm-fNX>AWbcYXJ;M@IxS zn&AL`I4QJ8&^l>g{y#uD%*uu38U(mXx_hr)J@ehkj#gL)4BUDSX~ZxLn^H9-1H+>l zm)q?^?HQ)QvK-tzuUo?0(hS%nFNhrK+7;lMf~{&gTvHSF$M*I%9)8O40HKPCO1*wJ zxNFMdSV5G%K0M#fC!d@l`hySLH+}e_hc&mh1PhD)GJ53KKP|rh{`=l}=k1j%R`nP# zXh7dSFT6NYqwGf?yuVMszD=zy`|h{@VZ#qP;iMB+FJE!=F-O1f(kzSSPCf0k=bwN6 z$EB;DdUD1I<4!nz!YNNZ`^=Lwo>;PEal&Md9WyH2)O_!K_bytpXwj0D_e`5sR1|_u zkcf1V<~xa@B=Cj|!=c^|GFFE^JGe+R0R#7l=L|F-W?ET(;a~Ws9mh`N8Wd3@A(xM% zu>c#|)scJ0@5vH;%uro2J}l}|2IGPq9>Xfa)10Hmyff3Jf1#6NyDwNR;aGg`zdvYe zX!I6@%0hvfO&d@cW?Q7Z_XqZ%Y=6S`4wd*nBXrqM7ZM+0x*aK z9v~AE?t&G8=wHG0+J?olx(p$&Br@PC8Jv0}cNj3RZZe38#&*fD74S_B4bf=4AiscR zDG2QZm%CrzetwT1AXOyN7Egu&ipOIy4pI0bP7}aCCfXw`iYKa5%uX*K>}BagsKQvBr8PmURN%;=Ga+`s6@BaR%Yrcx*T<>afcx$e8~zAGv$AuG=9@!os) zw5D*|wwkTypExin8+8 zUYkAb{)bOH{jWFQa9uQ=j>nUypMAE+lNavjXpctknSPJ=p+}dmu6pf_xxLWmz2qKyX?#{w>MSExd)i5n=<`%W!GY)G%nT(Cw{SoVsK}rTl ziW94NqW(Z)nTQpL1UTp@44D%^+*(*N(=hGa+;FDTn07RJ@eZ*=ZjH$nPSG3^-rvnrhL!)$!;)P#8#efhgBTaEK>~-09|0Q<~>qbSTcuw?LPWMZeWQze~p)8H& z#9cOl(u}1hJBzabsqEh~B&Gv{500i%R%_eQqAnTezCDW(@ z30n)5=kwY+U?2_raDINs=jKga@p@hUyZ|rA498-8iJ{j;wZ#bT+kV@5^8QE<+K22|RXQdm&P@hp+OK$=9m;2cXs!=4^raLACs%a$)!l5y-OctAUrrr^f{gI2Z8vE07<4&@l`hws0k;g~vn z5DoSN@D0Sa8NrS24>}+zfZY~?k)(NEQxR{P}U0V<_17AbS-$^<&xnPk(LXfX%wzg7xB<0m@$Vm<5=FA4MVPjtfyTS1K`+z`;v+V z-)TilXgWdViL{ z#EF~-MQ3f;A&SYQCvhGQAu|Kd_n~QCK<}|+dcpTU)ipQ6>+>Y8X2V*P0cCf&?kz1* zQdTi*_Ux|~EQrU$UVl(iV*X&!sT0oFuwjF#Ck071wWP-vK$$fy0k$m&;-!DT;=&6r zn)l|b&d>rlG1G8+ec*mI%{ctXqgJn4VVSzu7tqus?&PPv{(z<=ZJMPF_0h*>Tzt`m zC1s^&PCWaqH|D@aDk>>U#v-<1$$6TjEXJY43EuQ=RPBIsVsQs7YHmP9eIwI>xJOXN zBJYR69S-);B}pYy`wrU&)_QAu6f7v?%F%+O5k`kd0wrI;lVYZ8N6gK3VoB7XOOr!0 zq~(HqH00KtOgMoWR&Gj(K_HYdd4WS&L<8*H#zcE?cUZ>_;>k6qyOYWIO%fzqsB4-* zyeF29=`6Df(z%G5LumzzMzT0$Mh0VGX9ynmozi%>!2dRIqKL3B(0I5N`D?`SZ{q%7 zhUifvIzaf}Hto)qZPU@p?&=r`3MCoyodlB%S_PMX_?f4lNhIPYop{noe>u6Ru;|-` z-@f|Ftbac9Y&w}vrBjz)_V;vLEw3nVhOegPek1$A2~4~1!TtmKfBM;HKYjPzguk9y zR$ltV<1>niO0K--$~mvS=JWe!Jo3=h*WU<0_{A4qQk3*B1B$K&OtQ@!uWBf;V9)@K zj_9pmsh9>{1mNP(WG_JLSW5HCGVIOZOgNb%wSQQ*I&4s2`=*`e4~E;?dQ^6gB~#$R z5ur7}a+JB`_a8RQ;}tuiZD50j#aOfe0Gx$e4;wuv(Yy-_*-*~@fzsdxb^%#FN7OuS zVdh@EHc<@_t!TtO0b!>1@ zaK(`FTr8eMmx|*oGDkvZ!2ycEIl|x|aIjyH#wBnVR%eYL<&6>kg~%Vh0S@F?G)Rwy zoRMks7+p9Pf_DhmpmYWx8Uw$g<0TFeFy5Ze0#%DOEeX9Z z!izd)aHO#i4ucX7aP@Fi2E7&LX2O!?h>rr(T7hlTEXj^JR*2zPCWVq=nL%dE66?2j zoZ7>*xI}A@48zmgbxGSfO~yN8-J^5na$v8dHC^xM=m7YhW#`;s{=nM7pv|VHhF*R9 z9D2yXD8mhMHgQ9#6O=t>E!WW zeD?9wDYv(@MW;-iS{;uh;_==+d%)HB;rk!%yz|~Gu9$q=t+$Ln`4q3)8|jD~arj}E z{r$29pD!pbD5xke-?Vw_!XJKm_McA!w$e<4*`53#*QFc^FF+R;u@E!5=9XP(+!FCP z!`;1x}hstdoa&e zR940cu5Z3sSX)zf%J}0&Nvf%@gJ71ITzX28B^i#dLrlU+&cvi?WjYWL4#;-Rki`i* zOWJ@FMiQwkiXLpz&`k&pLC{X zOy&0YpmL^-V{f$6!G8>vl(iYGvhLKaN!5f1P=j5tI4(2|)5^r)C`yk5wAL9jlkOvGUnWD&mm~?nhOthVnVFCv0-jDAe{O9kyN95HF>Pipv{Q%56}-=a z3{tGdew<{wGk4qCiATjS1<$MEALGrDLA&PeCN}^YRa8`L+Ony-x_ZmT4XH#5_QpQF z`}XTUaO>7h-+c9DQ*+ZXqmHTUUb(hvjX%$S*vKPB9&v;$a^cpdOaAuvf`S5wjapmV zjyU3o?iJnKUN77{aOoR2Zd|{v3a)o^V`FJa>FCj8TH0DwEDBv(+HG51{d@1d{p##F zKYsrM_+pnVy*_u&Ip>_0OeW!T3_oc28*}F__~Of}ufFct=bi%)I%MCW5CH!4(-JVZ zU#1VuiGlm{9zLj7DjG(Ti5f&22Er$%nO0N?cSVT@lSQQf!`6^ZV;5(eZdu|{($5wJ zUIz4QS!u9s!%&gX8RyRn#N(;WTdNl@TiMbQwpq5mzC}$Nr6t8};nv#fEtal(+%6Oo zDk(Lsa-4^j0~GJEGC->iX5{pLOvL{9%#7&c=FM>9>Cj$kHCi;ws@OcBoQ@gFG1`PG?v{(pA`MT#4)Lf zqX1&AS@m6u@C8`5LtR0xA3k*l)7$uGq(#K}1p@so+9LA_Sz6(p7lLU^7R8Qu;>~y7 z4>vS=LIuSEfA#uxa3Q$!*xU5uoyiAAXn@2tY*e`Ilc*ty;ct z;dd8Yd@*3xi!MBG#j2`{F1iRz`uS&{{ph2Qk3a4>h)!qBc;fB(^Cq2pP9QJz!Tay7 zUAulw)taic>o#xN3fuM@Z@e*R@Q{7?A9ld7{U3Sc;WQE*4-Xj7|A2#sKlQ|n>C^6p zcyq{*q2GM-?I)jnT2avr-hIj9CE!@V?Em%Fyjinm`U8QAita2YRIOQ!5>mSk=^+O0 z%t9Y^{Mf4|9NS#K-q36XOcgw^*PB+fl&YiNXPJj}Vj>xG1}T|oXkl`UURj)9QWW9^ z*5#Ib9zQDxY0X63AT|v_GkEf~Yd3G%R?CZGk6yjISCsp_L6^(pmSv05wr*MP3M8gwciPDX_#Ng`yiVA0sth=3)Auna@`gfmiFcpcl>LBmY=X6>wf0x3avU25PT z5Uj;biw;c#+H(*}rdi_in5+ZKpkyqcX*>9YTo@GYax4+uLAwocZ+2D|8-<}}Mr^?% zA|$k zL^2-av*2tWu9l+S4RDes&!XD{ZW&?#6z-}9ndSv1Fp4Ak=rj;I*rlSr+0(g(X4D665hRyg=KA1DjY( z#cevym<)LCG&R9?<}I1rPPyEUJ(37w5J4F(z2F)NnPG(u}E_Y$>LfR@#+XfGngFBq@2yh zF%>Jrv`jngnRHg&4<}#Y%q^#{nj9F%yMzNc;}$WCI_*T$T-Q@2w~)!XIX2!&vae>H zPn1(MG$|9_0q<*o`!Vdwm^|51GfD65>w<7vg6x7{0YnJ?gQ3Jeefq#nizgC=g+=he z+9MHxsBwLIFT|`%=jb1 z3L_OML6A$!${L!QHP}JWFX*SHNb915_OI?`R#>U(`LK-M@I@y1*ji<|iJIY<6tS#Zz zqn!nd<2K|~kkAtbtroUbyVDC`R#ud{gcs@YcsQPlcw7?PFfFa%?G2UK(1aDoOR@(d zrL;;bnvHQYO?4i}-o8mCN1b9PpV-a>mJGHW0~-=)ZotNj z=%SFkJO%;`cGO4!8+|^LB#}rW$+0EeO@$(GoX)p$lXEE1&Ehw5NCe0=%ockyJCg&C zFesoort_2MPWD)tEjNRM2!}tN?ULT1@10<4iWKu1hA>DX_|MWbZEwFwG69#CIRA=k z2K4K7_2eu14j6RZb=Q8m;PabqzQrZG=FNKpV!+c*KMjt0$8ER&{nAVK8@7LaUH#g% zRa2+lfn!6xq^!KLzRpq+IB|P@$#~2u{JPz@+;S^Cxc17+@4ox)hHZ7zrri~fDyNZ=!Bbm97SYruM6dwqVaBiy&&z$c%2^6mL=xV?T| zN2JW~Njz|Tq*})O`<-`295Mo5N|ok#kINH}MaCR|0zC2QhwsBnz`~Sdf)QO=B+`Z0 z9dmKw+5qaeLLrMuvYi$Z=3!aR#L+K<=%JB+wizy(RKp$7V8F+r%%#cF9O{@eAT&ci zmt@)NksBMEzF)Yoq_i{?42psP_alnPoLJP_Wu{Dzz%ZO<&|U#0u^@uY_O{cG&!I>N zh>J-XhlQO<*Bq3cI~&H>oo(~PqoO}ij)Y8Lp>hv0A)d*krf_?{g_}vxYBo_EinZ^+ zEIVS&TehreXsl~%Y4ZntKCh&zG4QMcD#3G>hRUB_pRZe4_fV+9<1N;7qCUphol~!! z8ZHdk2%YvHoA{nghTWnZnkzdCm9hUcGc{hW)7v=h!}yp4^b_EKdmWwOL7bf;y8}lM zKSPs5LRW}N`1CVmPiT)M^*Iy|p=g=N2-z9oFa%}L@}O-hOQvo+onAO!&sb)cZPnUw zk~jBxCv@JS>`7`@Hfle>n~m+9AIclpIh*#*!eoJEjvIHvhaY@+(#a^2QskgP(>%p-4w$?wnW7o^4m1ImTYZ_>mtm69Vn@{qic!!I9S|0gUBcd%!8$g%At6*06MVfo6R6*UqJ76tN3(&>bz#xWlX2Nw&DlLlipsbn&>Y2y~Z zH!$LmBP%NVYnrKQSZM<7f^<&PEJ;t9q=_H#@*``YI@8(CNCu+s*)F9@vP(|mCyOWP zu-hY*Dw@vhX$iwZi)EQk4mSjWu`9Qn!ZL=o z=(<@>GT$bL@4|1|r4iE3Nx$37&f1CTOcBdbkaK3JNQCc15_G1DZlm*oyGQB?W@Zw1 zduF+CB;xn^h7TXU@4ov*V^Ol9sVFeUeR8@^_JD9WeD^)m7A^Yu!t*akC(uw$|NaAN z>$jbC*4dh&9eU`Y7hib(J=3Q@@bII(diOf%_~Rdb>@hejyl~E|uZ=qTnA>lkI`z(J z{y^Z+5hE6U|NYZXKQs6Bxx-Om5GkW#z`^D#=9ve4q7Em*$nbGR%S_kgLBKSrDEQF0XjeF279>+Rp(?y<^!L3?I zwv1srQt4STdSD)M$mW6Y&^WFZ>KU4NFZcItn&I z79*P!9y%peNQ9Cgc%fU`8k!pGP$`n563O;dD#7z&AW&3LQ0a9S=td4UvpUb8qdNC<->J?G)7mZzVdeZRcbGS`uVk{1 zq{q&7P&Gzb^jfR#C(!T*aM0E|!M{pPDxt5$8ji!ooUV-5-vaCc|;OYI6m00C^DpHl0rDTc@&PWQIX819gJ^f<`--d zb7%J>yECeG06O{TxG>Gx4eERW6nr<#xw)~?H-dnnK`ToQ9tJ_xh(MKOOH8mf7%&6L$+N-a+qOxbt zOD?%&>z3+^F1p~WufDwa;!D74F23lZufP6s(%I(}6c&QN{pOpm@0c=W(BPr7XTJiU zv$(wM{rBEowPtl?WzVMOmTnalZ_S_o@3;SzLi713tAoo(gAPJvq_*&pV@Cgd{4sUa z>rj`u%|N*9cDppgj>c24N(52JP#~ZQV2qq-+`_KGJ9%WWFqjtzddds(0(o9lM{5B> z^t7f&I->DdoQ$1Wh6Wzc<8gc3GWsVtGW@G4iw$+_+pV%c!wCk?xsz7DaJUV^{DM$^ zA`w}$?uT?T1)GfDpC1m_gd)VbHm?8Z zqj_$ZR903Q?MT2Wv#2{k=LK5T%_zz!ra6utFkpD!-otD(>7xTyPbE5*t^7XHQ4fok z<6N+`+#auyRFIr1Wy59^Dk;ee=AqACSPk!6?Lh1`gN+KUX`03_#@U0}&@ zG*nSV@iQuqaI~FD0eprFt|xUWzZ-)nvN&{S8Ipgd=+fe1lDLvY*D)hctFLc__382W zyx#qW4EDgU<4zacD1p-Ec5cfGZrQ_)PMMWy>RNeOw=+*aKb464{GntjX=-Vo&!Z@M zDy0NM`6VUAuv2uzBC_a49gC>RfrIrbiu{O!j$~Ldk&Lyqw!$(3C%R_k(om=bLY-hJ z)EbFFpui%)&&r~#8#KTOfn_Z$wdx3J(2T%x>o;wHeL9s)0Hz29f@P&;sJd=D*(%h= zg)W_if_|QJ>UmbKWFV=X(%7S;$2>MTENe{^$jOu+F;y-zbjy&|Yn|$x&Sb2d0F>zr zz_YplmWdNasD%~zaE9$VL2YFVvre;`(+r)hxwDycBTjlbnJ}kBA`Q;q+y;4)ceNT zxNiy>kwIt6Oq~OLr0tlnc{;VI-1(HwEIo%glkIF7%E=nhRF`;z1fnGC#4r}aSu_K$ zBpV6|y|E^?O_mzV@!zc)C}Qk>ostj4)xF1oX6XAd5r%c`rPf}*FNc~%nmP=4Xv_uTdI2k-UnJFuy# zDG_T2gX}+W$htMF$ftOA)+=-7%>MZO_gpRnD$hOdMqShIo_ZUKrLjLovm=^TQd-{F zP)9UPJzjqz9<@|7Gsy4~5rAQwSz;?ApyvEZXIlT94YmuYp?1hZ|3C7+1J3TM&i8-L zzubH0-a9ojlbJ~-g(MUU3eu&Bv;|Qqu7bO+vMac|>V9mi$ht@oZ17w`TwLD+S*l=r z3rdMn7D$B13M7FPQfD$L({KH^bKb9<|GjrgVhrrQ{k#`3B*V^u|0=`yP7WF`@MsxjMiGPdW9PnNWhZ5huW***~t)6rrMZORfwjV4eK$QHy++mtEd zO4T#aQ&tVhGi`Fpg%~f>f&u?1DAo%j6PvdTFI&_t#>XdpcAhPF;X(#Anj>lze^ z#>f_=&2w|s(2n)13)>-B=kv|w>cC_a8ex})tzeWIlI%3)rLvH@(PuvQdDxEUoO$|N4?iN8&n;Q9?8fhY=dni~`RRT49Dd|6 zpZV-(zkK-@fB(DZA@uh3_O|4ZwhdL`+@79dq42?rE?T;D$$j_UyK~pBZ+-h)U%U2e z?QN|mzVpOqo__YBhaSA?=9^P#@0GP{ulVwpzIyd_Pd@d;Mo`MByj6DtT2oI3N)wNYox^6iN7x zjvLdV!KacDQL=Q+o=PV*r<$^dB5b(?`mzyiYR4sJ2gT%5zB+O zQN{?`ylf+-#@6|CXmz;#J*^qfQE;H(vT~EaXj=&uGg%mlFS#cDL1+QV9s*3`lFYef z&=jV`hEq#6mwelq$YV_*!q=;0KC$sMSLVnfmx&OuXSQRbc3BvvJl9Pz)KQTmp0Z|> zhvDNN!t{S>X?VGP*Ae4pTeqg3N?nCd3V3^li@Y7?`@ z&NbcBga{ccF{#VVB;%Jf<%IS6{Q#h@`R#9?gFn3V;tTNm7ru1GNyop_mGY|G;Uj6cF*uWE$69d}^;CmJ<=>OnF7jN3Q>4E!y{H?EFcjw*rJ05)hmKRq2 z_LHCf%*gP_rJuNT&+zWIzy0m+d+#~l{MHRuTyfy=6cL%EDIO?F4Coo|w%r5w`Oz^Kmuqo6{IH-gj%TRTIT%WI@!ohm1isXfZ)s`D z;-2GPD^@OcC?MxjWh_VhyzS-E9%(^x=4p7wW>lsT!E9;Q5iZTEtiVbaD#&_3;Z>#D zTJr+_0OdIiXP9TN>kNz9tO{Q>v@$lVL_|=AHo~?wl}n0>5!*Nb)^zA}0zDCy0XeEf z$iqq`zNfl4$$A_Y0bP5I$y8&oG)$XBW6}XxeF~ltq?eLWC8{>cK5%&&Ivwu2@1Add z^P8`%U47cS&se>7^|!wMH8^>mefpUd&pfqi)vBSPq3f=_8kKY`Yi`fnkN(wP22t4D z+)^qO^ZER|`F$s!dw^CNLk>A~rtgNBoZF&E0P0_Jt3jiEtdizi$tWB>~{_cvRendbF4uY4Y62b zGy50P_X8Da9~rt18j)10DlW%CB+%~x+pe%?0>pw^l<373RVdmnZoV)y*w}y=H)2Ls zWLgjq+Ld1o;g08W8OG;Gglj}rLMpX{6ph)n5T#1RMKH5%5Z-XQP{XXoF0X+Us^uv5 zB1EBtRYm9nYR{;;gAT?2Fe0rf(~B01sEE3(NGEQDr73J?iloKk#d|4*Y-N+;QhzehXEebIpD*a!r3@BG6|2ht*yne zZ3wyW24S(VXJiD@!YtI){y2(PYKF^TwIB^$D#;HR&qFsq3M*sd<7qfAT-?U4P=vtK z%9dpn`F`Y}ZinTOXa~2)8K4rOShPWxi8@%FJIXPiYl`&^c;dx%lQ1(iGmxIDYsdYr zWKO22-TSq# zMG()V3vc=Tn{R&i>1UjH(kah8^UUo(x~*Cb&N$=r_q_MKuU~&1tgfb}rk7v*{g3az zZ|l}=*Ia$g`1trOx7-4+w&Asnqob1#|LT|4>+sE}UvT?jM^2V2(eTI#r=Idx=e~1d zXfrJ?C}{ohQWf$oc<^w>_@qsVavUyN6QTx_jDFckLUBhv*O_vN%peGTZ_P61NXk;2e=3MIE-?*k zLf{*X7im}oQ&s?68P?EoXfp-^c?-5|fX*i|5s!1~{$T{PbWJOZ)(K_=SO*hc7#n(+ z1xPuIPNAl*16kK9L$$BHg=JPKv5x#O#10|ltPnaqDImhe4gDQBDaL%i;8);l&92j& zX@W%9p&4y#dR9UcM*{X%7+|DF@W0KCCU`*DS3~ts1lI*FP2iP@lnhUl)1W-0FD;>% zLHQsoC{ohVM5KTOMhDUwDHVJ_PI+l~la!0i{*>!wJQpYXxcx(I$YitlCK{fo*? zjd0#p$G0>}d1*0=1|uH(V#jdbK=^NEHjJe1n^#An(h$#LA9ZoXyXhK)De@C_k7VZSb8f+=hyc1RRR zTEIRBoG}&@P*GSal~IbH>rLbXBg()bS`wy;2DGPbs`0Rqh}Hl^GDVjZ8=j|MiC}jk z95M)q%gTTO*a9wwAXIgB2Zlx~ex|<$7(_xBn^C(IvBtwqSsSQKCvJwF&fx%ZP zI6i1Ht{SJ82`qKGEnuyBt3mL&v`(|a6)s~g^g@)u5{^lWR18PYoNTHk?J_zkq=YB5 zn80taR2+O@`Pum3G(0%w7BFifm2znEgiisETe>d62DK>JZF?@twP`eEj8NSo<#~+O z_H1f6$JIC@bgjV2Z2{tVu|S%PaWaXlu^&_*+&hjo6A|4QgmvQvz{FKV^lcg~6sssRAnZV+m_r?`U*9?P4Mr;9 z%Jh7Y-i%YRhW4vO927nxs1NLN6<22_of6askX*h})@mm-ThXAKnfM=2PZ?oq#L>5n zLRA7aA2U8+YmV8s@qW0yG!VlTvN7ID$N6e?T zY$z8?E2jsTW0gg|JObZ|$pav{bT%4etms-{C}0 z)}&a8ODBb{uQW`{8l@$Y`CdY`s@sU+pP~dm%$UOjtpFicnRiNFIGLnjW@MYHTeE~N zYXK%*Bx=J;77aTCIKL9t=KxrsPPb_{cdYB$fgaBIUtTS(_7)} zw;iGbKyK`L*lV>#DxHF_ND?)T@pIcMhyw`tN`$0h1Mw&AU>vW@l-C;1{QqcXYNuzX zF*gXEPjwhk$=J+FhnDD zrPHNIyY?b}oy%|Mi{wrrX$L6JlXPH~JaV%Fw&pvsMOA`XFVAoO9-XkY_nrR|}P z05-i4MOYJ~!*5oR0q6^wa@9b8s1%}WlZ(XFg4cA++OB*?;0DE|=hQY93B_rHIj|W~ z#K#tGlZZ%!WH3Pg7A_&7VjdD9^+3k1kZq|ff|Fbi?+D6uBGV%#y;>TeNS^J$2?Vt$ ztMMpKkU7y+^*=UvLQK_RoF?a}`owLZ}t?ChuumyhD*$t zB2E+_JHy0|iGEUuI$@b#S|m40F$I(7M|8gG|9VIG{|*~iCsweCQO08wlE$`{ruLS! zE>_Z>Q>ltDf?5S>y@E-qwag$gym(C-RwyO!*laNt;xAK{DD800OVeXy!XfDw&(1L4 z>~+n_1}Z9tO4tt3BuFs85(03-0!Kw2^?wG%KPj!2!6t5{_+1DnvZ z2LMd7a&lk6Hf=oBUr5tD}GEg13_ZTy zSels`ibK}KCv#Z8IL`_rb&BiGDjb*wK0U;15`>h}iTR27?UL_z@ ztr|r+{(JtKU7zp3lLqb7r4Moc#_aBy$yi}9?w5=CtgQG}3{|N>?O3CTz^jYQCapLm z2~=!ld5|H)YhYrmtGHZ?3!zFM+=t`SwSF=2o6_BbZ9dj&B`A+tem0_Tl9+T8j@=?XN=xDB6_OPu;>Qh9m-JzI@T%(c zCT&uQgcfap@|Y(XO;;>NP>6wq?%4DKbAIgNkXMRAGdip`gz3W}cM#`)$RyPYo(ojx zDBKPEUnP@+sRnb(=y)W}a+xS_unfI2LeU0cCaeT$rbA{&bG9!cT^Ck@=MsicriHQj zv}y|X@c+u*+`lQ+etp*;6@i)ggS(_!sTK;wT$7t^awdxtu&&zMQag5y2lzx4ng!E2 zte6{s+Byit!M#Cp!OFpg0+ffPN?B8>N~)xqq3=)uj2q|7b!A+|`AZI;_f*^*hKZAWL?5W4Z zzi<$z$7D6~Vt zv6qhko>kj~j0&m76}C}nW&XBEIQ_adB!?0sjyMcD4v`aBlmsp2FrC1PhFD_}kysqp zi4&Zv%P^(^vMInx+YX~bsK_=?n2kn-kw}_wQq)vHO-$An&*AYc zY{83y4uDvh&L&=H1m#T-`I_w$EvCTySMFDRV0-ut+`T$!Vi^h{YzDL%&1Zs~EcvnR zW&E%llqZ82)~E_yDEeHNz*VS?MI$(3kO()7JnUWj3O&9n6^y+OHD9%dXhb&*Xl!Yt zEE5S%g&EgFb=j0AKRuKUFl|?sdk#a}b&aS7@?bPM07-+RWEBYdI$@*{1&S?7WH4ED z9AL@jSADt)8L%+{EMOlMd2rc9WVu2wub8w&Yo2-Up^%Nqj!p__>gI(p#pMtUu3%Y* zyk21?!KcD_8`D@An@3MH(D;=5m{UA2cxCdz(%OUy95P1nwibI_U{cmAE zQ*y47p1fl63MJS~5~5@~$)gF{g4@+0F?m1QoB(R z(m=B4B?Wv`P&6|b!^`10J|rTQpb`=w4%PrHzmVi|R2cn#QUL4FbL!^_C2c9!>xzTa z=or+a7=C=!)jg+J#U;rDx=gwWJ1P-mnt}=vESp_4H1h~8AD{?aDr+(brIGVQxT`}>_7k)L7-3ogw+2vg&j=Gad>5O8(LEHg`s-*6DaIr zTdoI}#Sjh*ybP&iWey02v1wn22-sx6oiLJef&?WPRw0?lVWvBr@UXz2Ffzz4&CGD9 zLUu%wd&ESpaTK#+lQIuVdIW1rGs28HPVoXX^G_@&35IAqOyZh86)j&>W)=h(7o<0c zr;eluM)M@>8^Nc?5*M}#IcSr08wNvLk+lPXm5u&PqI1nyPQt>Ve=j^5WfU^W8A#g?E$11FXcQNmcyv2Gq*7@3~hozht)GyaH&=YIGnC6foS3N=OBE&xv*Bw&{ zxC@T74WS7m8*$e0O*QQYd_7w_q!M8nwHl%~Vl!DMcEdH5@?^TpbXLau!pl>GEw%~b zVuYs1q}P~b6M>trN}KR#BwD%OhByThnjxwob$@s=$GllKTT!MfD>(<2^gqngm6d2@ z5MI(|4iocm*{%iO!p1BCTL1>YB8XOxKZ%n9oZho!oW&3>qacTaf61KTIB_i#k*k(tuu2#de zmxAXRL(RccIJDc+4tbg4Y>+U@4my&;`q1Tab#QPHzA=rWJP6#%WgWyRR&`LeS<%VH znij*XOA;1Q>|^H|=gDkejXe_Bsj%=})7*{FEg|ufWnHs~s$2p!7$*^F)Y~muk?<~9 z9YRbC;|N9B;ff)8B#RWN~(y%)=1Wz2* z(*XwonJ9qNPSiN;LfHpYdWV>*EW^m-7IY1KLV|#j&4JnSiJEJMc)=gjK)dO4aW@^o zZ;3pIElsnGhEMF9h&Kd-Lu{onv49lFWsTdxfx%QN-PPS4Q@?}F(2PV70dgUmD_6>y zOp|Tq*@~7NX`y2ghpmpR=ZvYgt=qQ`Y}+x}l7|$!ij31nrmgq>mwCa-JHCA*|LJ~!`5-rX}M#Kwf0%0A}>EuYNqZGwraWIgnKHobPz>0BJGWbEiPbEh4IMa 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 DoFA36 literal 0 HcmV?d00001 diff --git a/doc/images/beast.png b/doc/images/beast.png index 604a6d9bea691b3e2f13194ad163d36a19798af7..eb7528ec9d5442f6d12b1a1fcae7df72c32b689a 100644 GIT binary patch literal 148154 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 z {FzE(pX>Av@fTCLXI-L0fd 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

1FTuy6lNJ-+c2q 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

M zYu9etwCUie;YWdR?GEhNu|x3TkAM8*OD?(OF*UJ!!r>FIeaQ(gIQ5X;Ap88c@BJTt zcf-oxwpy(}{^LJB>#VZ`6+ae~E-x<&zLl5#(wDv@;N<`Gr5hd|zVN~e*RNkMA6edy zeCm;rkzWp#(=@&J-h1VJ-hKDo0?04F{PKhO+ox`udh>6da>|jb1vF~t2(8yp%4E6u z){h?k^H1L}z0lR~kK_1-FMQ#7=bg80+qS8xsmH}gS(feIy?bF{;pUrfmMe4Zwb$Nu z+ieHf(IfTuz3v$=e%cnf&g?yF*OMf67^*WNh}o<`;4k(DU-;IYmt1+zj@?W4Uev>j zUVifH&pSbYQ(3uD)Ixvfbo&oKc+GXUJ!0Qy=s)i%hy3=7k2(Fgb^RpQgD;N!#diM- zSKf2URofqUWLdv+s1d#86;FBHOHQ0`_mRYFGH^jL0?=Kv5J>#szTO)@bls2d+_&=L z&wt7x7o2m<)3)i0t7{9e(9d?vz4LQ7{@`{ih!|U4_@|@+js0c=+Uda z_Sc^BqSH3_``u=9WYySs5PNCbm*=fN$i92ygI~Dvjx3ry?^l22*kg|sTrD4MdV2bM z-@o?uTW&n_#5KS6tZiGT>UTZ7@UGAO=(c+wS$WyDt7=DYUcDS{{H@=3sVvT3ulJLi zZ@K>a|9sN=>^Glx+?KVYf=rst_@O<^7k~Z-H{84Yq*I^vq*G3oRWuk3f1 zUVr@$_C5HsKfU107oWa00{BE7sJ-Q--r$?pZ~yGK?@i|73C|AyBewsot1qM4cfmtB7O z{kQ-4!*6==Y1`KR^_On`hpX<|H*XjD_(=WY*PQX&FFfwP-HVrBbMI%qamRyu7Y|;* z7ys^=uYCS7^NZ(&-|di(A7 z?s#C=%=ENeky@j7JT2FUTt{bgd~#x9Rj<7$7r)tT${Ox=I<-hXyOgQ} zKVNdPwt)>hYE0V!p)X}+HeRrX@hvUcVZG#N5-!-yj!wLk$!$ndg@jQFq%gV$I%6C; z0EygmRE-=^1e{~2Wj97V=+eLyFV}RefDUY>3T`ni!X`$eD)82sA!IzwYo^Kpwpg4y z(k{BRb-WaTtS2$8%T1~dLnf-I6;P94&2Yu|3}i4i1h`}^PD?=598ebk zmYK&G1~Lmg8~kMHw7yEt5&MbVz+lveMqjRh;;zCxb*)BET&=koizK+icOpSyg<8u6 z#!`f_y2!uql>YAn5urDyKGh4)tZZh6tAEb z+)7>4DL^e+xD*|ms;;CM^_f+lZFRFRlxYB<ZNwR?Wb{1_1^E5wn6+&}QA@ji~ z-`Qy1xW^}#iRZk>pkFZ=$00c#u-b4@79?$}6RA(`fzd7>J`LI=A;=Dld8=Zn9qc>! ztU1Olm8PA!a!h6@+?;tMVXu?TOfSyPE)C=&`nAQSWdCwE2lQ?B2g^m#-LQ6I zTJ=U8M6xc?=1Xv+TsQI}-;MIJ$Z|DkF!ZV8GJqjpP{n!~1(Eh)pURVw7$*a} z$MeG&aUgk$QdzD`Ev|=g%xJ?LQbpB5n~<&vWgJNb=#@I{F~AoYwQ6+C!+0NdiXmy? zU_^k?fqpw~1wB5Qs9+62ib{jVs|4CO$rCOOL(#&)(@pb6Pn`s5FW^T^Y?NON0t;+1 zeb7J(B~cU(BOoI;WK)&pkeXf?Yo5WY$g3gSGPfZg&Lw`xM?}dH91~zT5OO*B8br=P zymo~Pr%JY5wD^huA4N>VGu&Lv* z3o18x&x+Sw%ZRtmbDn#^Do!u1RkZ&nqjmTGOMe@%Tr)&Sms6|#q$of4?Rzi&!cU6g zKi`slxEVd?lnpO<(uT91v_ZB@dIn?l;dGGN&JRJgqN0r*WA!ey(W~<8ec{S`KmJd5 z?qBTxLcXZy9dpbvr=Nbhz{0P8{p*kB zY6RISw&}Xu)io$YEoUoTFxsR1`+{Gk)>Z5;Xfx8Y3R`SVNFs+X4x8d?+vH-$L<7== zuZ*YtOirw-@JrjS<3VOLm(*uVfkkNPTDu!vA-Z>PJ41sJR6x3GfxQyp>OvfU?}Pik z_``*l{@%OJJl!UWf8*O%|Bs7adBw%&B!yIqX`c3zPOsO`n!^*dTD{xt4$`909Epa8 zduci|v)J#ajW8Y_X|+Zg%q>mwG%vGakjeRC1Xjq~Z?;}XFdJIqqeL~l3uUV7PJ>e(b)K^ zk!F2*&#vt|9*CpH)a3ZW(&F6@Oy9M$z0@}&L-oTp44<%d_4>(C0X8m42tg3m(8LBl z+%>aw$AkOtdT>GhR_^G?P<+gmiNn^9Y+f@wNKm!&{0YlaEp;fN2Gz9OH`lx2uIYOo zUX&8F9tTHk96f%^_@=3$+}e-pq$rec2A!0W*dTCcmit%U@X$Rw7h=xYrdBnce(c&~ z51s0z^rLc=B+Ae}`X^CI6%eZAO0i;Ea^b-;I3nXQXU{N*0&o99=UX@IxNkQ;i(ot{ zB2L@3VdLcRcq>+mZ>Z_GAZ1y|y^vkyitDz|%y;FjjI`p@k6VA-VH2_tnbJ*%Sgny+ zI%49G56aTUCdswD=JxKT*X#?Of!uDnb1dkk4uEBmyxoA@;e;g--HFIgb7WDNL2Be* z$6B>jBg1l!=G%QNNH)XewPaNe)xuUi8gA62+7i$`J-gKD_ScO!Tg}FDXW&5|=_Oen zxuvW_0o&xT1JyTcLFhW2Boky_3;m-uPo8k(`kE|@D4d)aabXwkHX98ow4*R;4GqcS z8EUm==jP?6t(lsfonPv9x|=s|kV`Z_zm#Of@NjF;@5_gn-9NW~W_HUFTW4ox1(Uaz zJBthR5A56i5vt)GD_@Hp+X6IW`9{H(Tra`_` zByCxSAt>u`pVpF&rf;V73sno+c-fL7eg%~%q_ym zr7T-R8v$k!f0fWy+NlC-SRQHUITV4$(MSpvMi%`-(5a`jK2wB^vgi?{6d)8D>q^l= zz^SXo2zi>^Ln}6GPfibihDb487|118tF+wF5uf_B0hzO>NhzkARTATP!6sp65^q-#55WW4w&V;vG$|oam&mARU=y^o>r4e5(cI!^mdU+%DvrH zT5)cz@@OIGs{5A|#|*J6E9YH}JcOYbSBP8_V#gehX#uiyfFlgYFwN(1n>>0x8XZ)u z(6;z_DO;qoibGB<8O7BA6+fP(8nMKd4V4wjbyejj%piHd6%^k3nxSNgT^QA8Yv-Y~ zQB8_QO2>}Y_~}y{pl(N}xuFYuH7<3W%2HFp|#R4*)<~3-=;uoPr(i-l=Pwn zsPb-UaPC>j0X+-V^ABtnM`Hr@7g`O8EFsRrbHW6#`YetP8(hdJsB^J)h%Oi?cI@t! zRr<6ktN8SaL{JfVnP0}ogl4&J6)Ud4;D9<;-5gdRilRrSa_eF?L!l-MYR^X$=qURe z_gzY@P*EZ`AzgWLoO-!#JGuz-B11cZhVIx#xZsqDVAKRcilv>-Zg-bB?7c2zSUbG1?ZVl?IAK zy>xJ}$IE(-YI;EDARMsA3pRyzq9@3?K9>7MQkoxsuazmL($QjRvo)(^teM;9lmLpS-rHe zl3R^)CU^PZry!<$mQ4Ef73nte+fSS-!T4t?@32Z zJnh)2XFqx4QJY4Tkfccv6!iLbR_N6TJJT;GyWwU+P;%C2k*EfH>bGe)T>r~{PD_HCF zh=S;z{3i{GLktRDG#upDioI`lJmim9iKAVOfxjmP*Xouzz{fW zYI@{~gDwoGvVtc|RB*teXlF#JYF0#%sHpDCQu5EYFwDk>aJwoYGc6D zfssncEGu5OfC4DYja;=pW(R@C04S7w0m{985Y<+%UOiNg|LOa;e)N0GKmO5=thk`v z{p3g9KY#mIE_&4&a|`Vv&jM(x@-&f;9LY(Orb%2It~G|rT9_2&+-z^(zG=B-8`iH| zJuxZ=MX%i+3Ca-CZOvuc&qh|0Y3l+BPp5K+6+ z_WfvVY*LP&>AidQ?%gvoGIq%3!=x6No}K9|%*n-Q4mE~HN9$3vyu7%$u+VHYYxQt( zVX@awYt3e>(TJi@4M`c4oD|tWeoLd?jC?njf5s_SR5r#a3?m*4DHWdbl>wiW7#h=@ zl!mf4Qxy1=lNT^+cmx9zg)u3K@U}Ht@w-ZW;>p3TjrT;R-hz4K$U8hU7K(?%6L-s7yCyt6if3Ub9n?s(Y@6^Xs^30dtm8D zoumwl#hRIgEya~|YNz@NY>nd2<&!HMoX6JC00|}%rzt@RqL!DtH4A_<$4FtChRSbc( zwp7I~OHlHnlt%a7J*mZK9V1-B0=zgJk%u0eHRh<-ztWrNYt zm}?#36&#{3EN{RNiLK>kt!Fs?K!OVe7&_ni=!Ek$Vc|x@>Xyxj%uY&RFc#5%EO#9%VUe4VcLsT$^<5{+oleJ@ zpYOKk7Q2IPT#q+wo?JE3K)wK|Jq$K?5-aKsYn~-mup?mfDbUssEL0GbD4V;SUV-*2 zai_poM9v9JRA^miwDe9O>~aBM%}oR*_Dbi_UF)tKMPDO|#a(eF)>g zi)fZl*#keL$F0zDD~~_*$U#$2&Da&0qmpu2>8Ve?-Du&|5|q{S+q#>O)x{3DU*)YS z@YaF3zXHouy>O6goTctR5ny=`1yRT@v}M51Yl6NOZtOZQdD`Y*J!6Y9NF1$Cu{?~j z|FtI6y#*W_bi@O#s&!{A)rOSZCl~r5^mj9|FG`IGaI}MH(EQKKOp`x#r0Eu5UF2-F z*-lJo)Tp4!P^7Gjp@*u1)8-`VO^87>B!*>*oJsyOPhR`Xlh?>EcxZ3?hj&chvVH%~ z>CQd77Q6lY7vNj>@C_qlt?1}OMmJ2gwjDZt{FX7tayz^nZEIsQDqKtiWSb}`>5?tw z`AG{-S);;CewWl4s=7`NhaB@xModm!B z?32zv=S11K(tc7Dsqdz)8XCmue&YAD*ab^O$0rcOFyipeEX zRp+jC1`0^}z~$wH8Est$0X7vW$`psLsbBp6J>?x2Jn5&~XMcRx%&pt!c1|xpw6FcR zzwYpjBddmMryjfJgsrQO*f=~n))06pg-eoU0UK-@tg1er5CTPUN&l*x?m~W*21}P$ z2e#7WWmzF)>FJb!9>z$;U@M=|O*#)p>5Obq&3iT4PDR_;h8K|*#4uim2)oLykWE~p zHh}{R?Llk$V^nI4u;;9F<@Ffnd!qGEsbnPCw?THY+B(;@-C2*Fzc_M|fln`=`K85P z5v-cr_|>m|wbSXuaeVjo2X49cTkksmNoj)Lh|J$OYRJ19B>kkH4wAGi>k%f-ZWQ~a z*N*`~+exq8>o${?{7qDAcu`Gi$w88oRC;ItWn3RB(!p|jIT^H9kB`?Q81@*9PN7j^ z@Q6UJR!O+pTGarsjO&8Gg1EMNa&4bMKDR0fQT8(8C#1zSpp{IJc0N{lQ89vJo@B%n%tz>p_(6@qqrh@R=WUgFu!Ll$nqLfn!ud3s8d{9^6x34o9`d3@m zE9D_m8tOqBW{4Mv?F(kFI%sveE`=N-&W-CUuOIO#{|dXyhU54Yq0W?lOp3@t~FJy3YYK2L&2Z zjj}}>_SonsfCDZ0sEze zb}}et)sYyWH{_MMCY&D>7vwOoz07sPKsAVt6}Amb>6wG3)dy-4Nm0kx|~cK zdWzB09hWDkGn{OQq%IgKWa;&$ln9pGPG#tV2? zD*ioi&rvVyFb|Xot}||Dl@pnlyBdh*>d;ws8njkjHG%i+l~?OBh74G11xCdy#nq_> zaZ2r`QcPXFI7!6a_bOly%*3kCSm6aY~PIESMuMivFM!usBk$rxRXY z4mXBJhDRDjmLgOh`$%8__Y?Y`%MA&fmE>}lrWK{;Y~!H_DJum2^n5Fz$0lPK7Dlp# zn`GyXrv`nTEM7Hu9fy7^*!o1^Z?G}KI+v2-`mo!3~>iD!K!<*}5*5@#z4 zLQEiOIOr=}H@PM<;)X>|h)pk~q=(0-^5#N9WD0_O9Z!0;duW(Ppy?7N`*A)SF7hjK zVlSjKVswrV3-?5+CXH{qOEkaJhd*Nm2i^Xu5XUMGY${wpG_O-`^d!JN1d3KDPQiyJ zd9XpKk$Ngvsj@1R{8#<1(o^|}Qw6@^j_4HB*ZwH{YDztttOEnPP1^3X$h8`eA8gHD z{-Ol6|72LM?faaYxNR4E)(`|%H&tAMhfmfaew229^fQd0*);5(NazQs-($ zyTGz8Ib!l@=gLVF2W~U~f(ySR2Z)zjYeJ1+RHC1ul1_cL^%#y|%qfSV6WXRNc&9{) z+))YBi>hC8fON#&+8nli`0%wO=RfCgtN()WOu5iW@7uK~5cHT$W3o_kG6Au#QsqL= zRL7pB&Way~T`cTi<9qm-V3|;OQb0yy6JzH+_xRsDry18GlXucVe}18}Yo>eD)^+uI zLp2c|WHy6b{!@@J6*RnBEa!Qz*Ukp*IEok^$N*C6MI1{N(L-06W_&8p=hHJ@xlg51 z^IY}XcFS56JmaJd^o?{0KQf)gY3ir^R|?`=@1Jeff+IJM)MJ!YY|UGYv z^*=#n;L-j^onMr5M}A+fvk6`?DWTC8V+PLVy zY>q;wH|WFg)~(4#o`vuX3FY8#h9NIjktcrG#4yYhwI~$q(CN09mg^%Uqk>YPL(a-H zDUv*ukLpLU7erF^W@tgUf_&meO#o?@3<_u{Q>lqVw4MFDObc+=T7HPhr{JHY+mX9b z8y=CjJwLx77Xc0Ts6~s+ z_;CNia*x7B5Jo!J(Ev}Ij0;SHfrzXv*+6IsCeR3_Fr!dBqy0iViz(DF*ghHBx~n_^ ziG~baZ*XfeH!CCXFfdHaa<#55)tDINeopgiUF}{`=)^#sfK%=Ga7M+l&Tc#U4>^9m!)~! z9Cq`ro3!10PM!vV0csMhI|?GH3ylxLNybBl5m-4|i`Z^LqZo=mp=q;)PHl+^(YDjh z3k-QN0LA{0JB5`2$^y+Y@XhSMY1|pb$|g@UT2%O9j)%G+aw6Y+^2 za>M5lpmqh8)N85ZD`S3J)vyZ+_al7-^u@_n1qY-oQ<{a7Uhl}0HW2)2@OfoPp|?v? zX-Q#iZqHL!9esJU@M_TG9jMW$N`&lMpidUlbPz(RNMk{Dby5Lt!IrU03cA{9m71ld z2K3$mnvzGHpL5D&bC@~jEHovI9|znT^y@-H_k;pKjFZgLQOpLedg&yxy2?C)ir%IC zDo2T8>@#lJ>8@why@n_dk6~VDDjVl-j=%G#t0!YYmr1vZ zL#jNn9JRm8_|7Og!%2)|z^M>^27()F`s$+EBbu&jdR&)7#5JY>aR|JM6==@9Z-NFFqUTXrqZt~m&#Q~YHt33V_+rtWqD9` zi?$>v9E&YB{vup-|t`alg*`2}t?r zXmUU?JcV3^t!`+N5QG@0>dh;yy}76A8Am7OerZ>QYZQU81Fb|EIv}_(22@&$Vhr@s z$QvRjK@OA>Y7jp%@|{6ej~j6`ZjchEE%Zo00F)2tVimp@p^BED$&IExkm2f*-NQde z|C+}KgbTO?J>D(B0${)Is&fI-3QeQ zAr>PI7*bJc3K(a}bnGY5yTnA;4)#@4!sp-1AVtT{99W4yfE1eoU{~NNwIYtnsnGGQ zUs}NiAcqFn(@Hy2!asAvf$L*I*AMyE!U>F?;4WMgnM?#?olE_YRDQbfeGab4PeDl^1!iQFB@0@ba-RynG@d^B_AQ=3pDuwG1SljO0NDIMfDMQedYrg^JH7z4lPM zNeN5CNvE*dBbu+3D!#?prM!P;p?fQiVemOobcHqPpwdqY@(;X%nUpkGQ3Zk)({|sM zs=}w+KpB-ZNW@y<+u}q^t-w6GaOSoL#iJXRNX!9nRV}0S5Njs6`QyX2iEV4>9BX$X zWrm@RXlzg?d$-z9#6|%n2oGTF5G70IsO}=^8s}p-H)&dAsTb56!_ARAjq-AF^<=nq zYQlIiSUnjicJefaK@DnH4=0f4j`?B3lne4314`(ay8uqIUs4?hC22u&AZ~}D=!k7J zsg-l~n*(NmIMy4NL|WTIDQFSldBjyYEJpB%2AVHekG#{jt>wiw7Fwvuh;qY8i!B)j zq9MFC7Q6U)8`hLu9MGvP^(|hG_Go(DpOXoo?h673%o^;gkF`Flneg{-Z@RuBYkLb3L z_#&G&_!EtWmlkd^kiBb=4)Vd$AT!I|Wx>OZEE0GoXrw^kOPIr?#2E+_SzeNhG1P1> zE-vk#pIbHDYBgG=6a(_gnY@j}cO#6wbHOXQ6Uvt~6^s-IKFOvIluN#! z%LS>)cb93_lWQ2t`8h1_&J`HbZnwLgUcK3Z1#t#+l2jwW$ghEkYD|(0T%-P=>L*Nb zrbp%^uBeZZ9BTruQg}`4Q~A4n&;$JQK33Q=jy8(f4)s&sE)IteqtRYusZ_U+^dlt;8J)PuJqrA?JIH@}-|Wu0WZmS*V30T~-8!3%uiA%}Uspq0$H?N5MExQ#wR&@U-@bmgJ2jbjVbJe)mloy+gS0g~DtEcl?Jh3Ng?=zUKhvnkS+Ct_4NHZw zxG=wZ%^I)e@1Nf5d1La2OAB-OY(c|Gdu1UIbinE>)0L?=8(Smf1DK41qTz4@!?Q#7 zDzBE3r`eS$bcEt4L}DRWq#0b+0vfoLskR4^g~OjTG*!`P9gk;$z%2(p@X9g?kn9Um z6?u>3xe|FQ2JkA6=^QP&EGd|^9!A)dd=fVdy}vwlO{W+Lhac4tu6A%49!!1*9IDCu z^m0_jnJQ%w3B}qpOVSdj8Z8Xu)jXWF2GcWGf7=cwZYZaAF4i5j((*VYnetOSl?(+= z5XuJ5SbGYWhOSI1Gi;Ty)mo?6ns@CzetSWI4(h z*|ej`p;j9J5qic9qZ;+Sr@0wUqp%`M;GmXg8)AjP2JgXU6Qz-S;*kEbDgb(*_bL@0W)sjFRk8A$$0L8T))zaobdlu zkZ%+2LFT89UH4$xO625rVV_`qrDQHU(ANGJ(IroCW8<x#~$m z_$@0cky{kSMG(P(4Qn0Tx{OyN&^OFakdbKtRjYO$Fze=v`!GpYGnHH&y*1rdRsu~A zJymi#!p+os**_Xf%Dp*3!frw7w#Y^n7Cxq0#mcD`e2} z3bKba(#;YwwBKa4H38c+Oe6GJZQ>cqDVXyst}25nu;4Ja%M+(+{TIZ(C8-j!?b5q6 zN6Vnd9nbPFe1*lOuX!B0MKPJt0@86e^$(!AJ|-p99?511+734E99D z;}tBIHC_s;!JRH>NP!tk!7(SF-cp4ioK7p7B2>N(Mw*ORYA3XVG z5#qrvxQ8hg)gg>B(~LcC=-toY6@YUWZZTG?A$K!WYL=!j`f4a(EKL(8J?a$d(2i7- zMJo4{f-YlHl|qFgcnJ?hW<0;iW; zi{rTA`Q1S>7!=u{=jTgu1cq@F+kXx@vk7v?Ru+zGVO-|21Yu2GXfQINJk{utU;++3 zeC#idLQsbQIKw-JsZ(Ou&d}GSx;EFr2@e}z!EI^t3fNAeN~NITGp+^u>FnfS5N!%e zgM^~S9Ee<@BpaKItK@f{J2|?Eo^Dfg?*z;sQCeW;Q}=~wEo(VdOAAs5D#7UMfx0eQK z*3Z*^uitI=_6znf+1fR0*REO@)IwDKwWyvqOg@n9d2wM{>e|5DG&C}9$UWZ!>HIW%Sjd2oF@aO5`^4Pu(Fvmvg znQdd*+?Lvu*J=Yk*d85xSeNkV@+rG8tQ<@Jl-yTjZF_-ZQkN3YjG`NP{Wu5(TjZQM zXrMGmAx_E%$37>>T;-4h-?rlRiRA{>Er(!$mLZ5;h}{L@Cr{}(jXW?F_pq+!(dbyy zWdH@Xz}UFLibm_&(ZMS(jAt|%y5N(B1?nlYAeYkf-d)|Bw=Xng+4y*@p&sVMAB)x3 zo<8f6Lc89cQJAc=ci&|fOOJoFx%yCsYiq;N@bb{NQ;}9J7!1(95zre8e9h9uHo|N& zPSophSTJH)UMkIvT!aP|vfGDE1=w`*Y5TG}a#|saUP|~@5P;T^!MV3NzKRjBaKjq( zI(ZDU+fJu1MHZA7s1!ZSXB-bQ^;i~ILzZ9Es@EGe<@;hc$x+?x-#@dww0QE9YH3m4 zar>R8Jo(hgsj0=e*>1nTZ{H)6;}av}tGeCpzP)=(clXqq4e}t*&FqascX)U>={QMy z5s@=N++FU>?AkfLc3l+3y~ zcLA?!R%%Dz#r4c7j?*Jdt!fN^lmnYI2t%dxQwHE!=kAi}+HxOFq2Yx1Zn?Qeo_8rP zyoAGc94UYWIdPTF$z3J?xH>1dN>?gVib_(h!)N4xs*E^ytVg>#MHi}Q({{Dyf8mfN znT}Wt6;;XnPU>XvQP@(HrG^fDAd3gxQ|zFHTojEI#}Cl03D*k+VpbZCMyd44Qc~V! zRYj%zVHhZaW@Q)>OISyNqSPG)Gh1x7oX@jw?W-TPXWL07vz?UG;9<>S^vA3+qw|(h zTS)5gTB=H!K4*~5x`e)X?^ayIK_oY6p13$Ra-*KBSfXyJq~TJt>`Jhlb)y+F7i-NDQ5spG*c=AQiHTt zaFVI$h#vpOXbPWNKsy}&=s|}ruqxO1e* zTMiPIqiReoug#@WB)2*g)y^UBjoLr;04$KUBXA}n{N>?npJ(0e$s||1(30F12YSOS z&2=pm*xL)=sMgZR;fQOFE->GYW6h4$vw{V_(p){R(?aDH1t}hCmX7MXu=%|-M$!VC zMTW1*k=lx7;aU*f!0XEnVChQf<=R`ps4(J_P&k$u0q;r}``bC0$C*5PIC_O`?6{J} zknqY`FRvt|{}DwHDPs?9R$9Q2x5ol)#o|vy2>!UR949O7OrgBNhtGXP{66@zQ^gZryYNGl+iB=9NFbP3>M|u2gXzGFm^@t>P$I;^eK|0P_Xn< z+Mvi5PA0a`UVx%uH)knII}p?x9^wO0{m9vX5}d!^SUc;I${$5QB*sw2;%NV_)M}G% zvDg^{Ohmz$!dZmwAln4Kl@Fnp$(@0F7?oHQXSoFHN^m!2MUdxcKQE;~lv4_xwY6rg z2`M~!%6p-8k|9X>e0wLl4yOB_<8jH5C@B{f)!P^Gzf)~yxKb0{TJL7Yum4pTR<84_`@ zv0+)Xn5Kf+B3CQRSDLF}kF&4mlP;l?2riqP-m5%@!MMRJ&PHMoep|ws$D`Ts>E?aL z|G-kX(gkP_2F+%hIf7e3qc(1f1~d)yZUoqr2?q#O*pFISx{QQWHI$A==+wrfND5Ol zbAxBTN6?{$N{Hy7{~M|oUK{*RCZ$VE?-hhgag8{}t~U~X+=_Xs=QdY3J6qb-_DjtT zLL&#OxX?M0L6W4y{mEr64e>j0dzPm7toSY1h=*E3^}_9Erqk&dN^5Gg(&~2yQX@5* zEtC6MD%EN&sJT4B3wq&|kOo0R4f_-nwMlP&ak1a)@z7YPE*qFajwz zO$7YN);T&hnr3-dAXFdj@Us5bY*;rs+>)C&7<6QNUDaA0MS(i%Xfp+tV@WbUH!I&W zHZn3?HsjFOaUyvS&I%7f&0PzJ9cWd{FhtfNU#4WyqYOhM`x#DUk4MmfG^YwyjeqHNjZhVGAO~4Vn>hrh(~$&CnYo4T z#7JGv)}=PG_r^w>vMQR*X06eX8h0RjqhACOtO}OfotOdg+AIr{WO*Og)>Wkjlyk*xc1oChejEDoi-gXRD+D%nL(6 z^)%Hj3yES>v?0W4;FoB5zvkzIE7hdKXS#_O$zGrrR z*S=k0?2l#>y`S}&Z~Vg z2er!Mp&61_4aGgTGXK)yt}3>u0`;|6CkF!_b*^SmIcnL@iW|y6L?Lk3fL_ZE&!k0BUTK_sul0rQ34xB-Hh@!I%SBd z5XmcKkXmfzyLutW*Yz;|0WXRJfV8j{Xms`yU?k_gDv|UfC`(&C^H@Sc;LE`i4$ZmA5q=KP`9IF;?wn9k(^&NwtC2<&=$Iv?)lZphuvir^AXZ zm?~Cu#9|i@8pIiSez-j;3r-sWXH<%huRJ4X5L*Q2DjLM+mX$-jYU)gBQ=qZpT$^g| zs$E?PLl*q{KwT*8Ks;5)2I>Mmb(OD}YM#`(C5b3id&)1hf>i>(HXJ++ZFa5vPeUFx zRZXSKXyB7hZ4KphB2-eFrQF1dC~8#N?|LewC)I_yE!1F}%vd+b!cpQRX>HoE&>TwF z8dsJ|6U~(miqRH{cpPmK7nN50pwc##t#buYCds~)im8>z%Qp#!dHkfS%1MIU!e-K` zRHTZ^2w`mdIPp#LLPz(Onsm|387u zgUsmRTJa><*Se-?u~TJZq3jgE?}IR}=G)}+;QIqF1oH%qn~eQ()psd*t|%>~h~gzEHjQcnE3Fsp zx1lZbnB-#2pmf3_Y6gC-UV>8xrgl9P^dD!bGw9FvyPf9HL>R1cy>5cH6o4jx9VAJ+ zvaE~2K!8gh6i2~W^2(8621(*jS(_D72d9G+B;T+WDYw7KOPfSO`mRTJ#e$P_#GGW{ zeeF>%4eCjdg0dMKhcPcIQeQ*poXfEBD#jCR%y4fABP;XU(N)au?0?rej55hRk^?(l;kqk-*%A#=Y zhAb;t)^H%~7wV&g9A1>BWk_i|jz6WE@pl^fqw|HZcQDyZ-V{36TF(IFV$TU^YH9;V z<J|55Z5;t#l7T%tYFQ<6f?uOpNbeJl~Zs=Uwdw+rCuxW=K6uPgkCp!@De{x7| zo-X6f?(jOjqKS$$%g?K~Q}ZV`H@Am-d*_G!ElBqET-$M3Uf+Lsve&)8+t`}Apzo{z?zQ0_SgGhaiAjhE&%H9Xy1zc&G zhCtJlhH)hRv<3$bVGf3}f+|GB24;eva`pk0edt9nR*$S{7`B_u$Z*iMrnkR^?qCCg zvM?9OJ0L6oKuu;mWx}(fg$W57l{}A7BbRE$f?{aB$xF~Ay|2~H;l!Qo=#{Mz2qM6N z!6b{NraYWi+G3$K7wD*Gf8)!q&cFL=+VqXoo}8XYzXiSece(hv~V>1q62^RP) z>pFDp?r@mq^|0Fyn@!h`hy7-rCR`+(LP8B_&0qfZca~iI!xvxt`A>iT@b0@`{_?Nw zbANdM&fdu{KK~!fL56-vDv9tQl&vV*s;_CST@p0^9 z%*V&&^{Mht)jC&FZBgq-8DaJ5tga+6#7az`Fu(}WnLV+W2#PRu3n^A&1rnLUyo=Ge zS{3ck0~xTc6WoDf`9U>oV|hDA@7KAmx)EPa27_8B4;Z1osMylD0w?+jJcW-o6rBc43LU#5pJE zZF?@UAMJ>HJWXGHcoo}4Q(@gPBB%8x z^C!}z%b`%w=mA@q^g5!*iv==+eEn+JVL(YyjucF^V<_TzM!GbSv|1K~2L#XCyfQT&v1b*Qd!6xH|*9u`I?3N?du#3CZeKNyYS zUD*wr@(fpps+D-&o;U;)YN{wr)`$iQdDDVY-LTmKILdl~9hnQ&@6;t=#0f!-eNDaV zizPUlgfVOWHZRNMmsy%{)|l+e?z1EZ;-wcqW8_vv(XBi@CbBxIOex=t#crV~I_(1c zBnc>U>#=~KMg&~i*g+D4zl5xn#(gNL6ZfNxThSLdR;6ep)pH^5llhU=mnunz%VqH- z2|uyaqSV1GWyl@TKCGQ`q5$xEC?4IlB(k*#V4152az#LcCLBj zWqBCQa0>KLsIsKoTPofUc~=j1z@U?Xi=b8I%$|(L5EkOO#y+M+4QJGUEfgfmP!DVv-Xh7ymRVzPB%s-6hpdUcLI|1S${{vHvjL(e`ZrMZ(6m(nu2?)p z#Sx)p>aIh=M@1n5YNhNg1n@y<2fnhf*e&Ow3XTqQAuT;`y=S~oNaVN=0x9osJsm9# zckEiN!0@IzRBnLx=>kXIEJ`O$Pco+6w9Uh(N*KR;!n@d0)#Q^(;snbuqAKzNB!#R1 z>JrWP%n{%$_*12L4i+a>+18y8{&addJw92ew%zSHXKGj94h6KPPMF%&xKnE}Ct&tz zW08)pJ-T-c=^Bo0c;_)h=PJQLBjX|(6KK3ejaqd7nQvR{<){RYT}LCzg1Dl|6D(=S zvH(7Vp%s02Jao7sk1=bdR2b6RFndk*a&i=dFC3YM{FOXD&TZ)yDKozWe|Cg|)SP1p zQFF1x-tdnyr&*AV)-1!*57(NcSw)=5^%TxQnLKy@3ezYSAb|cw$$*X_ z0te%qDmo&uTZnLn@;~xBL$eW)3N{iHS#bXXtzWm!KANZS@m=G%7DZ}!{0#j~5u-nM(Y8$R2A zemUBIP9L71Zbt7?eX?bGeBR&f+qXZh&>Mk<+hef6t>^Q*Z@>Qb`;X({cC-C?*Ka)U zB72vccHE4Xw+!|s5mdztRN;0H(o7Dor<1L;aopIm8pqB-e#&06t1ZK|D2S7zZnb~& z^|Z_$fo=;hOT?cKkra@yX)GO=BjWj~`ii=;Q$3ru}7RZ!h3weG} z)WQe}Nxo}gR<|xo2X}k)|NFN7<9Exie}5D~cI>#*gc&M0A_%M%5UThN%^UL#wbI#$ zsAT$+ND^T~i-UGqR=RA$&|2rvVIOh*=f_t|XM)D|>WNd<(v>W?fr~>sm zD=c|pl>aQas^VEPJ8=BcDvmG6!l!ZidTX&mQgsDT$tnrKP2z>yfcUT$yb9Z@r1ewa zfRq{qFMvGd&X&)-9#5B7dwg%+uH$|{ zVYu6;ZhSl*!{z+;&aKUWz%4F0%w28~J-dL15>uQe{#9l=D?qjd-P|^4Q~RwX>+E=M%?5<*7lgPE0a+4$$Ht7eJ#byB?^n z(j2G2Hr8x#P^ZQzJSrtP#3O=FE?#;ijL~T6Ft(CB(4*LCw2JStp)a+4dm6XtlH*Vt zP?y+@tRN_~TT}3*^O!@^!UMHZD^&?LIX5-O&snTP1&)f3EVwU4^l-YeFI&(`l7o5L zrgVM72m=Bsd2j6Ih^g_QXT*?$H0R$oC}vV~)VI&+pg6%LtvvNW%O zlQlZsdg@+~)suy;LW3uWT8J4)in2o$JHYd>h6`h7 z@-m2BeagzO_QNV?RDaP#|M4`^TOJ?RW{hgBLSYgQhEAfgDMYA9K!~sj%n6J0o`xb= z3bp(P&Lu8T3RlpgyreL5QM11tDrVm#v#!+-LK6&S!DWn8l%!eQpu!zyQ!z5pLOw}8 ze&YN9)pk&{WKK)3bbkS8o5RL%X0lkn?Qx{^U59Ka@gyRgAJ`il?&6rhia?eAs&Gv@ zTCT)QgWHkO;UoB|c7FeolMrn*pMRT=^;WE|NT08E)l3$X-uVJ@r;Q`J985vzu{vpPyB zgT67}NL81j1r7BCWe{m277sJ7G)=|u@VBjpJ|b@$Vxk)sJnY@{_(`CJ$#JhqLJH!- z%k;BB$_8a%mOiNx_8E=W0BFZx(U_Rm#97fY1Os$p%nJ0#!dp@@yfRT~lH6VK#3%;! z(16h67ji(9M9@|uDu%~0b#y^~SDf$%*0bt$hSs{h>DY{$AEJfO!64ny1TGcC6Z8jV zE5dXFKWIfoGA^~-Gj_44iEU13(z>CyHQA@-aylKKpPr^^>bv3o%^Q261^Bfv&65wy zes_D=@7iv6cUS$*ud3(QXN#l{ySvTi^8Cls)5CGyFJs$VCJC-m%F}dS;JeY({!;f? z5)TiLA0D18k?vBO*U%&89SYHfWIj4~4;FT$4ozGQ(bt&aXg1qTW681|(2n5Noc%Oe zocQv5wDoy^d$3q#y3D8Js~s-&c63b#g=Ys@(>$Shny&b1T@Sk6k+Q7tV!@8*>s=pcX=1Tr=@9SzB$rlt!iDuWPOp|j3Pn?x3EtT@#IYH3ipezp8kNH$FL z*uwI*E&YrGk&M6$O9c=zASa(Rsy-Q ztp9MZ13CW6;}eNF@zEgMgvKtrUbbf)EJ=G=RB+_att*D{EYDmQ-w)f}Zr8W&-Q)Ui zzq@?@9PEv4hju$OD+`&Wn*y9cQfNR0V^ds|STgG+74YBfqbOXGSd|B9NM{^P*{S6H@A=62DLD5u)4qpA~c)8gP`z5@-+B(eL z(5;*XLdnIVTf3G0QbXW^t!)1_FYEbywrw@o>fhhnzvky#aYDhQ12>gjojCkn6RtuDhBA9AP4G;zdQbT2|yEb+?PYdt6@MosYKD>~xwh^TYF3KCXY?eqOiD2mg9X zQzQQ&I~M(toBrnQPwlCmy{kORmoJy|}4=OZp0j^}P zCk&VU2{#AGBP;5+5`SGi6)I`l(Os=Qkqluap`-i3!lUGFP(Kt&Z#nK&+K#+5QTFz= z;&UP0G?gEtZuV8R*Qk56A_iKD`lQ@g|ES&;6Wy+u9+eKdh^ErSIt^UN)`SMvS?qfUNK=TpHxJOmoY;&WCchnnMI%il9)*PcB|7CIU3D-p7lxlPoPAORm-A{ugJzo zWtJasCe-RstDRA}@7YvpNU-NN)hCjkq3hEb74KfJEpf{!wxRQftDJk7IrxH zHZOjOakhMX(~ovggu3b4p#cbg0rIu$(M)Un(79pUcKrYdLgZF#u|L`^jWceCP- z!-n}VwSSSfEkx1`pctqzK2xk?kDSx6LAKIaxDL@oX=;}QXqB-C6SY#Kk+hd94Yyzj zc0KbXtBd50zC>YE|KWO z$U>~G95n8V-=nglivE191b%D+S9alqR;G!}4|SX^^irt{@BuFHPtclWmd7p-pet)U3|tWec4Qe+ou(U+hbc1ipxc|Z?JUPeb-t+4$w;4RmuKB z^-G$3$ti;@7fqD01e-kV%AM*f4dWA{gC$?0?jaSt1>7j*f6K86C2q(;;76V9=>lc2 z+U?bGa2|ax9?%`jp`Ne_C-W=Wsp1s2M5QAM2K-qZa4Ios9172Btrxd)9>vM?gY6)w zJ}4b$PX)+O#5E210~j3(a!+hzmMK$N=Fsn4OrH0I2f+M0%R(ndh$gJT!85zI!v+Zq;b{%?qP+i0+K3}G}t(L>EZ((|G z;n(Hy^uB%vO!{GWYae);k4s3KowEpgdVUP+()RUsI|epPT$lE{{qcxChCMl3O`B?C zN!|2%s>gP_+tawt0;N2!^SGtt{Pu1fx13h#T0T$?T?eq`k{i0g^{9DW<_U{GqJJ*I zBjBw--PuZY=hs(T8x|GXLpajP!1jPWDoZJcp(O&}+fNRSCBw5lQafwF2ByG)Jf$GQ z>zXv;B4;JcEhXBYu(}s14%S?6eVx`$G(2ION+Tbk3Q$7@PEHCefW2Z5%AQy^Y;1dA zcx1VND$|eXS6bw_q-OAATbz8!Q-v*g%4=6m-PphS{2zaK{nuYV+q*hW5SRb=_wir; zar@6->=S*`NMVTZnzko{IEB27&0nE<%5RE5}}Z7nBz_i#Gw zHiyly8M~X?gFWz%A0KaTZ^!+nA?UKjNTlCwF<8EO7=!Qjhx6$bBRII*XS$}@<<{E< z2`DzD6$_*B)G3ldj%k5J9XTq0ZF|@sUXRC@=VvTTOiNZ>ubU{GPe+UHZ|?WD5>Cg{ zZs>=@5IDK*!GS-m?3WB^&2BAJ=I#wjasiUS2}i#==V*k6HV8_qZKmrldS3)|DNf^k z2N*|`eQRPyj7Y_?+Z9}yKTJ&ggksUsCSkiSg;RVtD_NixemfcPp@!T#LAISjZs;T+ zAEQyWy+izHI6=bb#NG$JJDL!v)nB7nhrGB22ByxnE}@&6ZRskGY%oXd0Wz^&4X+)` z**FLa*YnfU`?l|Y{)@jlwszgWoIifJ8E@YF z{Aa`V)=t#f+gH8dzHc^sm;u5+v}NkxQLfQm@IcAq%i>5WTc z2-FKMlpx2CW%VT_&-6})f|N5rwmoN*@)0T^Ih6@zYFjGT6F;nz{|GW|`yVuuDRL*M zyXGLi#oMvP_1-WIv6MZdaAq4y)oM!PBavEE;&WWfRx@NTqCm;(4J{kjNSQDEAe2{N z$yvOfX^xIEpDuki?p7%+6YObfJTda@waJ)AYXaC6-!J5ZZKg&9&3yF0uWD9lyV;6b z85l;I_$^IU=vYW_5R*lv^qkJ4iYYK|!S_NAp&dDJUmZb&5zB^3qNa#niiI)@Ep-&E zk)2_t^o51S>dGRIBO$j@?`sODj7I=~L1KW(Cq`5{;(=pR@+gwdHGr-3nDbs_%~o=h zRks+tCRL^baxvTWuE>;gnM$QB3&o8r>(*GL^3wW1X#}7E`eZbbD1-C(;6cx~Rx`R7 zCunZGk@mXeMy#}`1wuk0?1{4bluAZ@z^i|uX!E)_h-roF3?^j}^ZQ=tGRJ6ArjjTI zN>UFqc_LuyVxSv*kUJ#z`hwsSZ_%Rt++7vmsko}LRW7`u+Bp=aGb*Pc6DSNFr(P3v z=LAaHVT}W~k@i~iDQwXM`1_K+M06yO1d(+biC96&^k^%e*GmrAr!1{EZ5nlNy;GFW6Zan~k!V;Ob$pBnCyLHv>&tLvW8e zYf9-5{NR|w0Tq4I`CPwTCi`?hxx1@|jhzh$r)XO5R!yP|Dt*R<4eu|SAYQk Xpk&-3misuZ00000NkvXXu0mjfj@}7d literal 247196 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

?U91U9 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�{G^ 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

`_Q~-8 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 G+x{P?gr@!g delta 154803 zcmagGcYIXk7BxIAnMvryUa>27uZX>aUat)W1VvCf(xi!kIfDfo0*ZK4R8%Y|1{G8U zl}JsU$xNpAliEPkX!EEWkB`0U z{s$Eb3H=*#rgW-Ae#V94&y-0dc#(*=T`1l*RMT00d1v#%x|*e{cK=j!6&Y|ERx;$|NqF|y|Q1W=Zv{$%)jorYwW#ujvaH?y<@Jq=FaQJ z-gEEu*Ij+XJ=b14?#{7$*DIP8|F2Klvas&|`rcdC)i&(Cy8ezEhRW08Z&)vp2;#rJ z3+@~(l`6J;c-PIR*NcCGs{c+ZPL?UA?)6Vt zE@N*0;^6B0ubRee6(q;EhMLk$#xpnkUE{{T->p1yjcfGm?K7^p`H5>+t$BIcyG&$F z)3%%-86RTC36lEXe>m$7qv6f4<3IDxK0UCwDoCDR$>c@{ydO+Bc8+@3q{`%j&XTX|i>$*w+K?xWj3-IRQ6Zf4u$ zSHAvy^{#3YKjzix_=4MJXADoi_e;~PhAR^*j@(-LF6;RFfmf%K?W&E#*tYL4zJl5N#iUvw>85MPocli{?VY@_Mj`#tci-M|PfV7MNS?`G zUyh1!oU?k_Qao5gw;URG#@_ZRSIcYZ#!CGb>9mQ`+ATxoT(jk}sVB?i#Vub<^9`t# zOqR@(%$KZ?%-;L{)89*_vMsmFSh0nlaq^baXAIkN;WLY*S8v(!%=PEoy?@+=_C}U) zFlpI}nG+YU7FqJ6SoR*-aKRf&a*CWOtZa|Dh+=#ddaWmo;#I1l$faftDV`w;gd{*8D5@gKy4h=&jlBOXCKikN_S4DmQ(B4QF^GU5ru z6vR}-lZdAf(-2Q1rXyw`o`Rc@jPM~ zVmV?3VkKe~;swNN#EXcR5Ni-?5icVe5DY?%SciB8@hajq#OsLlh&K>#BHlv0jd%yK z0r4(kBVrR`GvYnO`-m-w4-i`sA0k-9M~IIRpCGm&K1FhuDeu9`OTW7ve`mBVsq=C&bT)Ul4l`dlA1Penb3@*oXK7u^({&@h9Rh#NUX6 zh$h58h(n0Oh$D!jh+~N3h-O3!q7~7GXh(D)GzcxC6QM)s5nTua!iX>-%m@p@im)N< z2nWK6a3S0X527202oAv`gm>`V--Mtfqa>%Kpj1PtmXeZ^ic%e=dP)N*4Wu-P(qKwMC=I1F zjM8vQBPflebP}bLDV;*;R7$5&I-SxPl+L7d7NxT(okQtdN~0*9N9lY@7f`y8(nXXm zrgRCVODSDOX*8wFDP2M7N=jEzx|-58l&+<89i@L!x}MS)N;gm%OX)^RH&MEo(k+y3 zrF0vm+bP{a=}t;_QM#MbJ(TXHG>+1EO7~H^pVGf6JwWL{lpdt?5T%DHJwoYGN)sqO zM(J@%6DduiG?~&9l%`OcO6f^TPf?mi>1j&SDb1kt45eo&&7?Go(rij|D9xobkJ5Zf z3n)EDX(6RWlonH3LTM?b=P50tw4BlkN-HU?qVxi#)s$YO^b(~tl-5#unNkBKhLW1n zI!doldX>^^lwPN_p3)nX-lX&vrMD@)Lumu0cPVY8w29JYO7Bs6pVAgeA5hv#=|f5^ zrH?3mOz9I!+bDfX=`%{7Q`%1H3rb&7`ijyHN?%j@hSIl`zN560()W~pptMWc1getm z`jt`5RNbWdm+BGK^{Q)B6IC~=hO5p}_NtUBnQE}=2Gyy`wDJ#SKp9acl?7!<*{;+p ze^i=OgOov~L;0uj2jvdsx5@_P8s$eylhUmksk%$`B);x8)p<&v@}PJ-i`#!vexux` zd|0_a`IvG(K6|b5Ddj5V+e&7Q@)hMu<#$TIs#bL}evvm-->W`VsZ|ZCH7Z8+ylT1X z9A#YDjbEc#xe>pFPWg}WOXc&*-;sY&{;C>)Z#Y(Yu5zk!f^w3QRgS{jmnrYX4^S(g zQC_5c93N5C>T8S2tCbs+f2-CVeDL+@P$8YyHe!y?amzA6G zdu>p@pVRsC>NWg|YgO;4RwAxfU8%Z2b&6`F zGNw8o-}W^8nunA=l|(716u9Twm0#d~Xj1-#w|LwWKjM2bc)vrrQ#tcB<;Tjo%JIru zl#k-aZdYpX4W3dxj0fZ))dQ+)m1W$Gex+R*#a%8a&G@1pln0cp_yOPJmp+U;y;Z4I z9#M9yE>?|E-KUzO+ON{9G^!s}hgB{3|A*?Irq$0iN*_~5uV4=yZy0~WK%3QQvRJHU zv(;v`@K(9S&}HEDN<&u{UQ8C=EVEecyknr<>9pIdW~15F)9bsFy}h~Np20VbzV?P2 zZ@%T`Tkg1H>@{Q9_nRB8l-9HVG&ejyP^r`F@nSRz`l0MCEe#LIu54%DZowx!#{SXL za3<5#(%JIIPrn~M`rEfZ9by~Skg;`OI?96jD)Fd9upqrqe{&~Hlb7>owqC>Ux_e3&;%%)CiqG?~oi zimA?MHsdXe1@BmJgN0F9Z8rSPcB_@M33lElSOptz7i?0yjkBw4c8A^WK=2OUDY%pl zrxPzOC+`}D>~gzZE~oejPQ1Z66n3Y};ixzTd~Pj$$mMo&F2ODFRNW;{wOit;^a$O2 zkF2++r_?L-NxTf#$9v^{UaybyR(yhA@Ns@w!0+b+k{}llg0es`#0T>sSvVBp!a`Vx zP)MT@E>?&OiHqWqNGu+UMZ!_P+iG(5*mWAMwcF+B>A~;j>GStEy8F7_Zr*!NPj4um z3VS@gz1=+lpFfjLr*pX!6H4TB*=!E~`J9kFIbX=9?4DRI6Z05tHh;cUEM&9!qEI@y z5D&$&`FJRi$>fX0Qn{2#XH%&hpBD;)^OOE-r@ZIB`ySvQy@-vN8ZMUB zvBS*`_em@4G;_nLBZdMRMw6jSuh(|!^<6-WoPERGaED5+X=`n(wqDBW%ng@Gr?F)- z0kip^A3of&?emW}ZTj-}miCs8qx%jUbpISY^3RSYUeC>N*zPIkRH(q~h<6AE` zyts71f_1+bEEYqjM%%jYyT-q@CNpo8(+}YdGW=ZLP*2b_;Wq$Y%O>8)n>cgHBsb$v zE?Z>4BxjY{EEQX=-Db1f8LPDlKuR4V8aV*4#_l8}azLWQ!8v6>7w;^)WKIV?F9~f9 z2hiz4s^T*QAg_)<>Hy`EO_Hn&6$bceG zkYs#bpSR>I`8g4Z(qNzzUJMERTdEVJ=dQmEuC|rg$_Eh{i+yfDcgY z(pl`rj<$BQ$7Q#h4K@!DX*9b0euv5J4TR&_LOvJkbvbN3k)G}}m#;14(&G72pYr3%sls{oHc&yKjH_ZO7-IZg_3W&OQ6Sf8&MaE4S?UaP8uyD;6(QH?|w~ zt;deHG<~({LOTZ@| zs0R6vBv=W79Yvn3M1*K1R*v(rd!zn7Z=cKK>oIDz9qshY*XykwtKOj3yS)Hlm#))f zGTH*kOcvyoFXm!B-EM!xWn*F>$V4)o&&1RD9G{iuvRv-uY$jL8Mf?1*Y}{pX#{j&H zzt0~!BUvbBhyo*#WFi(%B;xTzJdsKl%H>jtE04@2(}hw#l}H1Ig)$4TyCas-Qf<$Xg_)DyZC8F)Q(FgZ;pK=Gy+}7CH|`uqXg43+PXQPJ;ke;{YQ% zP>%-@g6wv&AV5Vh5DW&&Cm>b|OC#Y*L=vsW__z!Y zbvb@_z-=>h8qIo5M{8TVR&S&~%&P0qY1_=*c-|YeZJj2EF9R;h#uK?hA=%g0?d>(0 zy|IwX=?P^ru~d%BR&%H1b4xPWLNOP1_e7$7sKmu`DIe|b@eNFsO4(#O6^q7GsW>0L zD4NV>;*q$BFTz+hp3D^s8L(n8mo5;zKzo&PwNhKAa$T(*&kbdcI=o<&0|F1#}-0Q{i57fz=#VtI^n{H(0FHIS~a~EJhH9q>BSDoMg4& zgC>*Rr2dpts3S^sd8(D8Lu3QhtOiPv;USdm)6KM+D;k! zf|MCA=Q~ETN2JW<0AE7NoXLE(=9yUwm(73t{s$g-Xu|a6@9sHr^p}r*=`?CukL>$) z#}7a4T(jhzPhMTO?U!G6Y+V2Pif3lO^x9jWeE-#lAAPjxt+(IUwBy%fM!OlmE($Hs z$Dw%;%ddem)|kwwye80>Noqmqt>?A^XVB$G#1*XNICk^!gHY%_P+yIn4e#qJ5C zcZ(;p<(!abPD+963JHhRh0dTaRzOM327A4-XfDU6B}qOuD3Q*j;(%*DlT0M@)sj#= zsZ>ZOQ|W9bol2%N_;OTYR9C(-tV{?5=Kr_<_Ca67>m zhNi@;jnc;z?2N(8kRc<)Cp%hmlZl29mKn^PF>;u>y;W~$-t*ZzYoA}VWbuk+^XERn zHV$Sc47~NGG1p&r#YOxD!o{Q5fkT+{qyyM1hcLGe8G(lprOJ+PL=P&vW(ad}twb-! zPiDUx!rU#pRLjPOFryjit^+PhdOng-z-@6!Pnc? zEtoxT-mIq{df>5%Q>ILNuHmbuL)+iohvC35`sl94KmYt`^^8sXzIy$`Z@&Lx!`qu) zm^OFyy4OG2`T56Ree#-m-AhYXuK(tk*=hkQdE)?}69bFLlQgfOACxjC5Tp#Wj!xHt z(hFoFB$hJf6s475i5JeQ{4X#ute_i|Q@co`2R&h{4hd!x4(tb_a}J{M1W2VG5E!gF z>gb8>!hff$N_^>-y1c3TTaPy%J9Ow+ zYlp7O(Amy+T%*S`>^F%}yo|0kUJMOgb9$db~X@tG*Mog8`;581&eCV(DZgmdVki za%w)8OUIM>e7v{ED~7YroW+cgD%llhF{7ntv0t3UoGk~_u!qlLE>`e5g^rD$#XNwKeC*lGRm{u< zOXf_Px%Rbpcl@=FS-fuZJKz0txcT_IlNP-C)~kzV&!02rna3ZU{KUjbQ=fc#(W{?+ z#=LPrueaFkZGRlpm~~$+dhM^>E7xxP`13D!H@>&{xz%f4`+U#$pMSlTd1phz(%DO1 z{jSw&#}o}>lx>6@Z=zBYV^&e3Ehq!LmA6UI z3rg_1zxdL)A_4mi61zW;q!Xxg0g=2@>Hs8pm*A|!M+uQAF&r3F0xU{g5|>!Poho3~ z;|5-MEmwZ+KFbvND`X4~i z#_){7T?#2MJ%>Y8KvRfv;LS&4k!T{BN`bIq5x>*g6Yyw`x3o4NZ_%JT)U=^X)G-zp zDhYaYqbD5l`tU77;b5TG>hSpePQBUD8}$3*xm?)k2w?b4Wq2A~@suTx;L1Q!$rPHX|G%O3{vjkwX z9y1G-aRMd>P*ykz<`q=#rnla0l&)2x#77^QIO&mz)1RI)AVL{@P0~Z1`;B%K6W)diy7x-Ap78xkis!grLZwVU(CSqhJ<{4E2mW zVkE=?>aE1Kk!rQYVgf)xi&e}g67+~t>I((*i~yhAQNe61vl9SmCI$#yZq7y1wA5*@ z;C;cN01Tbf9HMVLA=(frqD8E_i=Ik%O)sVohKA*eID+(6`vk87RES{&G)O&S$*&Mm zS4O3-gcL#0pvZ&MFdj#uF>qm=xG)ZxCK!yS(upwO>9%zoC z8+Gk%8l4%xbhodMdNEJ0hv^NclD*cxNGcTxrwYYvz}X#2kzymsRr3*}9D^l0_9o_Hm0Z`^sS&g)cFs-A?MhjzM#Dpf zX}pQK4D{Eqdj5(Je?5Hc_`w~oyt?{1placg#j|EFT)K3@^yxDuKlJc~2OoT7(v#Dl zeR|sb#S0fLU%U3hW*RFYUFwf-TKVSts~0U}zHjSn-uL-t_Wkv5Y~HltjdcyLeEcah zZw2$}M~CfJ1EzT3UdM})A!Hi7uAnajU| zd7MKWfn_#_ql$M>ejU6`MS=}VZ9n8BxTQ|~fH?aSAEE?HoK+X@OWJDe6H-*t7Trqf_z3skV+Z62l7j$iY00hiy%6Fctt_gy2KYHAjA|&G)<#e z(hAu-#xn!YJOyHl*dNkeitdh>fSx@j&Uzs`e>_-`VK5x^giZ+ zVNx3&Oz7J-i8&yuE1hq{$Pf%zSpvqJ<0ROnL0-X%ilqFnPx8xpNjSU%7Pg(#5mZ?$sN0 zy3VG(zyH4D{cS(({r1E6zB+jP;GS>3__? zd;%sasDcJ53D~u0;h}0X=m?cYlwgvtIUrDm-kv6wD&CV?Z6#~nf4e~|U`S)H;Nb0Y z2#9z^>^Ixe1;0OvX*TQ{f_{R$LMgB$ZqjhcTIf5W{yX zJly~w*CWSF03oLGUkFw(rU(#W6n-CyZV3a6EEoU)6=K~b7*<0*d_f=tc_owT zu?P6X$YeBs{hgwyPfWUBz-sVJf$RO?_on@dJReI8#Tm(ONW$@p23U?iOc z=>2{Oh{;$y3CTK>!%Yxsa^-4eU=i9*KAT7uX`ZftD2JX(4I(;5Xf>$B(5*p~2`&aK zc5G{uj#aR4O=M2Hx(3+8kOKYIV&%-|SY04T)8Su#`RbKLi{?G`Fz4?Z&P z#v5)Od)>dTXV|WZAjAtNiG=vrB<9({1G=C_b?L!|+D<_6@FeE0It6M&TRY!&2|IW) zb1Ac6-invD?)h!+--i$E*}MN}%b!1e!#pr~_T-1B&78M#-HS`+&z>`5>cq#UEnKp2 z;mQ}DU%2?i)r(*J_Q>Bm*)PBO@o;D7QLWu&{`>Rycm8$o$M-h8vFW4F8V?@+bH|rW zdfl&UU*7x<`-cux4kV%zfas2p0hlzJ2*`4VbZe@>5I=!Kpbvy-m7xw-@S3+&{x_FE z3amIJPz5==#8S25^Q~nlgpM+xDPXfAI0jL%1=|tyfWWGgpee%#Fo^(vyi4x(c-#e1 z{gVK9La(HUA%#Xx`ZSNV3Ex*i?Ue&}D8T*2w+ewq0OX1olLf#|i1N{u#D0*d!_hF5 zKBpBTlumE$^#y#sV9*QcyRR2rsNL-JW8mlxCE~zlG#rSgvY3^@N%=yi+nuC0GYqup zLM|506mq~@&Tlq3gU|+n7nJi}u!+U$Lecel9G-BNE6Ol$$aC>#ui&B|XBIFB% zLBXjk&C1bmvRFa$SIpvv*2A*^t-LrI{C4@csSD>kJAd(_7uLP>{G#WVFPb-V#^RS& zEnBp7#gc`~*T4PJOYEL6mp?vdyT;*hKrD5dHTyo=^6jooYuB^C{Iu=E-G>f-xueBy zJNnMj)h}+^tA+j#QZt~3Q_}7RZ=#tKOfs~b9AkvOTsEtyhr_PNjP6aa77=xL;)_$R zjYbOW;_zo;xTSus9%N5*t{u-b4!6olhC;_j9h_?j-G)#7AF4=x5v!{}vW)m)5S!qE zF6fcC8LU9u6>$Ml!GPPtqo!iO6^p7D(u+9SmN43KL5VoqVx+|cAr{i8B*sVYibW!! zzHXNjx|qR;iJm%XLzmHRLkq1lKvC&-T3lYg$K}Hpf%IaSM={m{N7+Il%Y@zjY@W~7 zWm5Q9Iuyzk`20o1LbBVaH#^&NrG>h$PHh@mnEp70|-;)e6a*su(skC0d>YVG}f}E z=a~_Mq1}_Nhes9-%|+}P%b1ISrMs2^OIw!#OT*YB%a}Wc4iOinctX=E1o9X=VmUKP z&UXsz^~;%Clrn8wE7x`z`{HtlDU0Sjw{Z5H+0QI_V=MdR*Sr4td&m28ZoB`PMT=If zS~zdznpMkQdU5#+OXja+RxMpLf8o+4%Nb_LbL+NlTJq#`d!5}5qrQuJFYW%1-g=|q z<;^<}{Ql+E9}XY;VP}iO(f-NO)yrSn-i)>x%M+Scp_~}7B@`Pt!9Z#XgTVo8C75dQ z)C9=DStP1h6ey;IArky3WRQe-afl^(kFyN~#84lhJQEh7{ed6ww~99ai=ZrQc(H}E z)sd1SE;XD`U+8T#a}`jRSVhYWCRYjYHmDmdoY=pKugbkej1Q8&BIZ?bg~4NHl>~UG z%t8=?AA%1`L%|#|7&g7~C?HgcUEnhtZ5CaJ#_Byj%NUn%Q8mepYtWrMQ8;pjdSz4{7FfSA#GmElGxsXZm*gy|XW(oy#b*Q1>Fd8I; z%77}z4X+kZQ%kvAnd5|NQXC?hzi*V@reH5nGuKGZW+$nca{#iHYJjXo4UnnWyqdY` z)KkR40{1m7IY^BapZHju-M@}mCa<=QX8&1-er_HcUB{fttX}o}oCRxMT(WfW{JC?U zXVxxTFzeY_3l}e5IA`X}#V@|{>I(H9iyO+H5&eYOX87mFonLK!=dF)_+_h`Zp^m1X z4jHZOpQ&G4_S{t;Xbe0%JyLZ6Wv0y6jV99fVHR)LLf$P zB6sj}Ej3_8ngGguoVcP@p#AqT{xT_XWf%sa#PLBD*n_&S5L^QlTGf)I7L85> zj6^{$k&K~OSxj9P(3jO|w-~!jR%1s?^RYIay)P1WnY$xl{4lo%CDD%_3Qc+@lg%b0 zp(s^5&2#`ebBsZr)U70c!zCpC6sFtz?Xdi`K>3=|i zaR8iyO|3%P^wRD|>3ItFp^ePFr@^ivj$9-{$p9bfOVDvR&So1oidgH|2&|p630OOs zeQ*;q`}9-59jHyTEWn0?oGMzVy`5Su$F^-^?x_D4-qduU4Qppl+6>U$&fd8hpj-aN z+e>CFT{z?ESu>_gU*524!OW?Xr_Y_YX#TU$%$&V=&ANuw@BT#s3$GW9XPeAMe2>Gw zeDucF?ce`-y!Fr@f3BZ@Dml~SXrYE+`_7ezREf5(Mc)KWE} z(L&!3366-25t&R%m>UEf_CHHN-XM&-4rkWo>2!i$&>O%>w<`tp=fG-F|1r*1Uo@@Z9W~&&-&$Z1sx^ zXTNjQ2FHaC5QYpRLZbQGjqiQ=ciZu!$M~az4(|Qoi#JznIA}6q%IM+@gZmqn|Ej*= zIVna>boxflG>m3V&?UYLIdSMU2M7xN71LHB8aq)j1v|K!peBA6`T;!s#21^Tj8ChF zAp*6Num_+)D#5M-oCkG|6uN%AIXKiz1*}SL25OrOJ29*uFk|viclo|rXm5ltI8xB0 zNxU4i-U_U5KJ@)~AgiKPs*I`$2}G1V3L!c0h2DPxsczUn#FJ@~+u&MC`K_)#5Bh(- z4n2d@4`nzSi}X0{Cdj`be=lQmMv~zG;WHWu`9cXaXMhpt2;QhiU>}C6h`kuxDV0hwlL*K1gf(>fMIa7s zKd>iM6_o;XIerMIgzQEo6ni~Vcnd(*Jqq^bUCi0_80krHtJuzCXYInSfnnd+1%%mm z0b%E{svns<29H2Jp~{J8GlqY5@{i1gbqYXE+bL-4+1GxAzIGLM{cxAC?LR_ao7>j< z*UoPacOLp|-R7NpfBkUnn%6gf^v#YH<6qjl=kp>&n zW}pp&sg|YyjFaLJfNrhc$cUQ;v7|!JK&J*d?Zj@OhMIdDA_rx18h*1{mvs`L0(2 z8UwZv0`SF)y98{w{Nyj;QCP+45?(w^1EI=)d5j0d$YAmx7(J5dWHb;;B;mkwI&DUi z({8kQg0WaMmIU2#QDCYj<|{c!O9>1$=#djMpEE#$yTU)(Zvf0}>EoIf%Ie zTKzHv-TFc<>BG?47t5FU!r4?t)389H{H7AIa5$a@yl8fep|q!Ax#KI65?8FrB~ut1 zIrL%jQZ`@Vq2LPGCWwY7u?s`-6m-0%>ASxgrJS6-Y(I0$$s?vb{OA+YAG`HmH~(kS z6Hh+%xlej2yZ-?2 zH12rw!ENvTy#KpR8@_MV?EmzwPj>J9^Vq@l4=&!h=hf*8*1XEho&MC6=}%9cy<+L~ z$&;Uaa?12s(;l0=@Ppl7t(o`MArnkj;K$BRUN;1uDAdbcdyZ(@I=V=NFxBf1@7!?+ zdtj7G9wdc967^E_cEal^F{+?fqH0oiCU$G$+vv~Gv6ax3k>aO9B|vKrsjvh!0(er0 zeLihWA=uglnD0PqGTcrJe_|~w1PrKX;+nw4p*D&VnX@YHO)*TKfK-)M`P~f3wS2FF zgj%#`q*h4Ks!2(xmG}r&1Sc|hVq<`QzldfHRwe57dAOD!l7*`f$pEVu#bCIHfQc9c ziAccjb@NVTcfj8lh^4c9=E`g;8V>eajD3NgUcb+6Hd-8vF9!L-*9~FC)9Zt_fyGlU zp9=N`q0?4@s|qkxC=39Oa;Z?a(-T0WR=5}=C14fAaw35a4tg+fi-9!~41{7SS`1XF z{sE6USrScIRp8{6e6GxMWxz^~jRB-t(MZxX;!vaX0tI_*GjoQril$4jU&u~sh7Nls zyS5qK*L3#NX69P9vl(z2#B$BdSeew$j%{HskxTTavd^|K4?>{$xdk`h#kyP2Wi8(E z)zYV5|8nOiFFk(mzvrxZVdibd9LI}vNFlp98cA(J_jaD@##H9&%MaGFnVbD(~J6Xd>!@ z>W}`x<_`zDT|QzjChYUruzc#l_~huu6xiePK)}aWa5*ktElBcZ1l2&HR9{T{9PVJI z2#Ad;mI|q85UM|vH=j2UgU%Wa(;^nOPZU$MX?$f6K!s0EWw6*JZxUBi&KD{izOTFj znB_P>by=SrLvy8I|7BuM9S-3dwGA#r@H;(!_2;tFP0T3iR90<*`{RPM&wXUtl+W}I z9$J{k1TAb3D>XCs*C^?MVjnRx7bz7ehI*ZXU2A6U8B(vovJBQ zN2bo2zj(#U1=Ht!a;)w5&%SRl={nn5`Hr*NJ37eIqBC}N{BxuYO&*!xb?_aw{L`$5 zbzMf%SQkhPP{abth*uIAFwG1;V5$LYiD-oB(t=ex4FI+MphR1R8HZY0K&@(n+)N4} ziTr}2f44-C1ZTl9M-b-0WxylQO3z5T=LDy`zuU()9xWKegq+A@D2Z6FGygTjfyl&$ zpX;l`Fi0&J{`0+pmxfOcR95xL(1n%72COPNFjX{l0)j!*$Qs(WMd5WFAnJf6%kFeL zZ9U}usAhS9FGckctx_rN^Yn(%JOP4(Gm%ixAI1+1`NK(!m<4Gz#l@?MGhj`E@>;vFnQ=lSX!Tkr50-n+5vK#vV zIEMYH4|P%I1yfzfUhQS>tcO7iWZ>lOm#}NS%%v!o-*}n32acubQLCkUyN|cE9z3kobpWi?UvV804a`$|O>1*ICRS~Swo8KoO0Qu!*Vkf;03R3% z)2KDdD-ZJ^f|GvNsaXVNM#I%7Qs5mv0CU`IUjWO)8z zd5*w%4Qxs6NP=AkOhWb`KJ33E9JFjFR|f}8j29*Ss#}g8-{UTO1eo4XCUFj-iUzDK zHef=ZlI%tFQV~mKm6l3a<5aO!B5@4jMmbnd_#$8-@mM7hy2#E^P22%V0<$0t9VlbI zK3`ZQooFnb>eID#*n-Jq*aw&~eQrC{*={loK}hR%nM_t^Z?`>=Ens)4$bk=0C(G!+ zAjFpj;_O2V%lv4L_CbSTFN(%6NEYm1l1MVpP10%1 z34mR`D&?v?!Ax0!yO(hGr?ydgy@G8{F=xsJ+vRK^C60|F(*V}oG=Oy;yEV;RH+%@q zVMdb;^93ph?p&UAq?t=<<(*(J1*^(1w+$UjG)96T9)FDn?fv8obD4B8yDr0=#xy)O zEJk!|$Wc2nIYM!*oS-cMlvNRFi$fO%)fG}1l(G=y zG9DT~sr*8W>o1!M2&btOpS}@-DmID%wCz#&i=c-^9GzCI#G|oLFquj8!QhI)1XP8; zp(o-q8?1dy*zfRTh^*qA3}`V0&G;oWEqEShUtNpKc&L(EWEwZU|%oRp@|F( zyZEGPnX3$d0hrWV{1(Xsm#l{f2WX|B(N@y`C9eV}<)P_I1YWdN4nQA`qNCGoYkJ1e zD6LgU@7O-i(kQ)V>m};b2cVGRUM4;0;;j#9l5ojzPGk@y(W`nN11$Oe5 zwj+Nwe)z#Q{?p60t(o%Zw7JvAji30$%thPU!FgR>ns$w@qfLV&WnG$h?Z9re zWtcDj6dL)Dqh0A~{-YNkyp_2i90HatQ0X^sw2oCBkzQzXAGa%T1B#hY3ZZ83X zJOC)5Zk9zCx!}%ul-(Y5{-~7zp8}lL)06LaX^_azd26X_gH}-vkewF?76K}mE&}Ml z$c|P)n?`gNjY=>}R^l@B{5)+8Q+#p^$*hn<19r33;|qt}-LV+Fk*NeWh%t}F?toei zrO;}&GQLCro1^YPk39-etD3(A=5O#I)U`A;j4XCXC31ilvk7>CdVS$!7Qz{JL)q9V zL2xXb86nz-rvW%<{^;P~HX{p$I5x_meUy1PcSWJj#9PD=Xp&{yv6?ou>va5%vr^Ccy9il#$x%bF>)2FQYNec&Q zM~9}PrM>OIyUX7E_=62wzWsdue;%Fq%zOKf?Ax>Nz^}W0KHPHjXmiWaW6kgu>EP@m zuA}x0bl1*z318o|wm1sDitQKt7)zzuxbW(hFhCK+1pCQ^BdgfTfeLXxgW53MHH5ONy#|yn0t}nX6H^0jD^U>z z%ZrMvqk;k|`qE0SD(J3;1_e)d*&_wws=ynq#^Hm6FQ_Q$7IGR7ILw$lX3Sc0q#-z( zGXosZR;I%-;##~0-95B1THiKWA2*VohSPvkI);}6-E$JGz*|1Nl>*fnRVUzDE9=FU=&Vy^k+^;yp> z`QSKI3RKMY4vn$%v-xvYtbOaJ_G4S8O_=}L5xr6K&o7O;f7;h{`U*k=*%dp%Y+zd>rc?nlfnXq;g^3Z23esZ1 zaRSQe2$&5_G>3}pCT25nm6iNySWN+Kghx0sPUx>B^~13XUgI1Ud?scBK(Q?HTE75N zb&~xS%S*SY{nJ4#0Vf4H7$8wqnQm!McNwy*3}v-)LMS8qS;031##r%1wA_N+#PfoX z`pNuLMVnSdJ*~tg2|iv<)WxGg0$H5o|Ec7(5cN^mE5JX=xEp^r&ac97n~b=O21tyq zXxM471{t6$fx*@9^|*WeU@XYOJvct$Pr{)Q>FxI7SBNCzL0^PSJrU?6LPQbh?Tr`s zvI3{B(uGP%QG{_rWU^uzYFN2K3Py@rvnmc;<^PZJS%=;VNJkM}RguJSQJ_lGr9F*O zogC|*sh6oA98yaw7HY;sE&E({-(~7i1C<9l;hzI(@cM_@zRT3(2aX#v?rS4j5eP%0 z*c(Qx&yx;er;JvQRpN00zd6{CN2}*vqr?o_3dOXIZ3H2xy#WPH z`}3QxZuxxM%QI)c)Nl=Z&E@JdnOTo7{oY`}v6!ZRnp>L>A3jdtYUA567qm$_`1T9n zV?!yWkBUL0*RJUV3^AE%06kH>MLmV>sMsl|JvzC5u!J%}Q5#0R8D<7?3qYM3odCxP z8oUPnpolO49|nbbuovOah~sFYOPqEE;@E)aAi#*v!V}T~(9w_zTbk{ElPCl=R8yRg z!GIujLki)+axi?CL^;g^hAZ}v{@*`&V(&?2ZyeI{mPtutV7l!ur~(it4FYOV(yF5N zfpgNLPXkI?ToNnBYoWr&!VxfCJuL)qN;#c~#(8w>qf-E0G#<9=w77fpJ<)U~)rUUY z=8osGAt0~U-|KOpg|&4@QkBfvsff=Xgl{tBo$Ts~VH=7qQa+BgW;o>c`eVuAiD<~{ zg?|jwW+|J>Ap>!8==%k(R0o=*`if%A_s{U{L8l@q*^jdb| zSoH%#2Z)>ou;4xf*v@5J#;Qljg_f7u$XN9w>@7Efxkj-IZdA`1J_xNjhCb36U|QGF zdHbFl)uV89P=1s8yvt}Z03vYckNl0Of1SKm=qzi7XhAzIzkc__?ytZ2WZnF!ldfPN zzDa#5vu4-dZ$EnX)8FbljsjblVB3xzJ>J5%D%}CczH0Q>xciI#m#NL33jNCSb{K>>2^%29XsF4<@YWF_F@GQx1?Z@HQ#? zM^Zu@swxfylGb6xM~zderr`G_%pfK(6@{>pR<7I74Q)yA5AF_s&thrc2+^eE84Zdt1zK z6Wid)fqQ5?YU|eV>X~O;jR(?mf*mV_o*+gk>Tgov$x-;zVW1y zWNT?_>qjXlumdB3hJE)w^%>0Ij`o(Orq<4`mcRe}?Z@xFob%zP_ugK;XhFlTR-;~r z#a4UAk>keB?F}2h{dmT`w@lrmX*qnj88Fmn+gsY(TgXod8U%PdI`Cv5DMf@W)pHz! zC5D6>9eNFhCv=4*+u?nUmhV(y>eVpxdJ5o-@s}`) z!;xqW#q-iu(Sro#n75+uBTlVi0#Q+`OD++7xE2R8#Cy2k*~UXzIWdl?h(5)qKSSyr zaVELOIae*I$mj@p9NKcb^B#_Dx^Ri`WYg^dh^ba{K(HU1EngK&hzgyN;lvXQqG=L^ zyBv_yJi-TSAgutrw3EQ1z8aQ9ME|%5<64|?g}lL_fDa&<1MgCs2p9|Li(}zHkIP}y z>CHYgc*!I*I@(K-oy}nN$7p4rB-<5$L!f&7ID^JW+jybS3-IMBp+qQGL+>^jaNlP|VO>v1d$D&z6p0*G*E7 zl*3rU!k%>RH8r9Iw~f=t0iD)jyA)v1oCYvpUI58;YFdsSKHO%&w5acB*W2w=VbxWi z&MbNSk$W1BcC{aCZPyT0wsmxh=);-o4uDicmz%(M#>WYIsLxdXA-$kFW4P|@zz>n( zO&-V-wBpZH;B;h{v5e`Lb{GO_#dJ&%gDi-Y+Cp)O0TmDRx5^OeP=rZD!4nT4gUt=N zD`Cqz2s$6Gu7NI*8eIs)HPAQ32}Fu(ZV>D$;?heHclBUR3?Zc8A*ea@aBd}`4lk~L zV~CXYUi}x75KqeV_LLZJJqa#-ULTo4{<~3CVi2Z@1acnsVW3Y1Oxgh$EG3~TP$$6| zS2{o#m0|zHL4Bd~)f_G>A;35e#L=))OM*$9O1Dge->7sl5e@hP{%)JKJAxfOIlGe) z#vjJ<)P%?AA&V0976l4*KF=4<$%c9YH2wNrZd_V|W?g_T*=@HtV>k*}&en!u3k=iX-E8AzO z&#My~LDbVT*xW4j?L!A?ff*o?4(@{@dG_Af>T?DU(4gdFd;q&zte3IR&qn!P{>;?b z)1LUcs|%lY;tS9hwsLJM5p@`YTlqEt)mu*JL*dp|I%GN=zv)z>IRyAL9X#IQw1d%0 zfUi*#NCG5DnXqT95fwi`P!Mf$IJYVqlmy_9BtHgq8Ymn9ibD@bW!;L;Ma>txMDg4| zxl72PRf850JtB?Fw9mkff~FPTK0q{wlN2Q`*`(wXr?aYZ>@1uWsLA9NaaTOjZaPFw zjUv@;8KzIZM+Jux34p*Kk)J@4a=+WsOB+}jkcZ1gh$XxjP>O3aly33r5u)o71w5jN zLXL|O5`}mj7NUME@gb^ki5eW|ip3JuWHogm*7wl}x=VOTlBpQhudvWzO7SzHcs$^7 zhslVGV=`p8JTIS12D-fo@)xB7Jw5&e@Ptxaj5_QVccO^xM5Z1iP8eQG99M?OUe4TUAdxQz$U(Rm;_LYq(aSO~HP; zTzwid2;UlFFuFPXh)&&kx=w>p*ZR-5Z@lp04_YuG;Bx%e^-oP+|H=D{C(Qf}7Oqyl zrM?Xn7f?mN39R94S3B3HY;6b8q1IMAk{;X ziS>*IctvPifgrWHj?@=el~HnO!Z!VYMV85B?IIOTb)5j##KyRYxtXy-=E+Rruo=GWU+4<1yW2zjb*$coR$8 zegM{VlPQk2V?8Haa_|83dBwp6HaYBYF|cstT7o&(=f&!*5~u<5VQTI-$TV>Wi-c zbz-rbPbV{{6rd=g^5(&N>3;Ny#Mh*%HcC@+_GY#Ef}wTL@XqOa90@nzWZ*OF)aTdA32hSg zt##_#2FWqCv{u`stw7MZtZ5wt8KL7s2;3H9%O4*ufBzqBC^RjQ@EVt`JE;G2<^!)B zgU$^2wO~SNJxzomRopfW72`HwkOJ)<#uv??Hj)C{@ZCUsot+$xBi5i2WA#zhDoC7x z{#S>?ad>7xamMNcXHpGJ4XLlNWExLYWQa8MGy}(h@T%q-APcTI;E^zji%9^o)Fp!c z07OhKFrVNPF-QY}ct$F03Kq9G+T6vUuH` zK@l>*5#FFmL!|*7D)2sZX%u5R%wI@KpiVPlBbY=Lri(W5nR6jC=Wvt?o7P;s$Ahbz z^hCg0fSHTT<#|jn`BSOhrbB(O9^mYA)(dUQg|eGZ1O@~`K5rbpC%_J<8;o3}Q`BHV z+S(S%8QA0`BJl}TImcsVi?aLo%-vE!&Mw}l9yxpf^*QLJ0X35P1^WPY>qhm3!{j)g zVHI#M!;4I1Wii{jQ9Yg=wn=>%988)jd)p@Um{U)ss!K0oiNo|vB@gej?`~3W8afC~ z8Kweo9Dzb}F*|xQhLMR+e&1=p9;CSyrI>3K8$`Yh4I?@}B069SG}qBlZLcMX8Dz(4 zR5;>G6O9(N6+gYKt--hf<%QP|q!F0lCEAfCkYNNP7PBTIZEE#sEQULnx8mrG*!D4I zxCh7_fIS>`wUS$Spv<9r<$LpKubQMEQk0O-^_J zj<(K2@bXY_Sk%g~*g$g!M0vWgVuLe=1(2!* zpV2%FIVQ-%j3Qv1;KOicM#Qx(q_!xXZot{p7*K^v=wMFfXz!7bB~z&iUSnQP!k|)3 zS2A4oIvl(T(-ld2gBYU&ZilBg^blG*sLtf`g`$!Tdts+b7qfmEmV&u_Jm5PGE<1k$ zTt^EHao>jP>d>3TViJI&Dk_4B7Z$=PL}fxCvlSuWZ?2wUvI z�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

  • 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 diff --git a/doc/images/message.psd b/doc/images/message.psd index 2332dec4f13b8266645efbb16deb88e7098c1c85..3411c20c8221fc90ad34986be16adb1451829150 100644 GIT binary patch literal 378966 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
    =ia8jchQr}d}Wd@|2aGS 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 t{>g$;exC9b@ literal 204871 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 -
    +
    + Index
    diff --git a/doc/makeqbk.sh b/doc/makeqbk.sh old mode 100644 new mode 100755 index f215ce4d1..ee5a7655a --- a/doc/makeqbk.sh +++ b/doc/makeqbk.sh @@ -1,4 +1,4 @@ -#!/usr/bin/bash +#!/bin/sh # Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) # diff --git a/doc/master.qbk b/doc/master.qbk index 0023e72a8..d8155f2da 100644 --- a/doc/master.qbk +++ b/doc/master.qbk @@ -8,7 +8,7 @@ [library Beast [quickbook 1.6] [copyright 2013 - 2016 Vinnie Falco] - [purpose C++ Library] + [purpose Networking Protocol Library] [license Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -22,174 +22,85 @@ [template mdash[] '''— '''] [template indexterm1[term1] ''''''[term1]''''''] [template indexterm2[term1 term2] ''''''[term1]''''''[term2]''''''] -[def __POSIX__ /POSIX/] -[def __Windows__ /Windows/] -[def __accept__ [@http://www.opengroup.org/onlinepubs/000095399/functions/accept.html `accept()`]] -[def __connect__ [@http://www.opengroup.org/onlinepubs/000095399/functions/connect.html `connect()`]] -[def __getpeername__ [@http://www.opengroup.org/onlinepubs/000095399/functions/getpeername.html `getpeername()`]] -[def __getsockname__ [@http://www.opengroup.org/onlinepubs/000095399/functions/getsockname.html `getsockname()`]] -[def __getsockopt__ [@http://www.opengroup.org/onlinepubs/000095399/functions/getsockopt.html `getsockopt()`]] -[def __ioctl__ [@http://www.opengroup.org/onlinepubs/000095399/functions/ioctl.html `ioctl()`]] -[def __recvfrom__ [@http://www.opengroup.org/onlinepubs/000095399/functions/recvfrom.html `recvfrom()`]] -[def __sendto__ [@http://www.opengroup.org/onlinepubs/000095399/functions/sendto.html `sendto()`]] -[def __setsockopt__ [@http://www.opengroup.org/onlinepubs/000095399/functions/setsockopt.html `setsockopt()`]] -[def __socket__ [@http://www.opengroup.org/onlinepubs/000095399/functions/socket.html `socket()`]] +[def __N4588__ [@http://cplusplus.github.io/networking-ts/draft.pdf [*N4588]]] +[def __rfc6455__ [@https://tools.ietf.org/html/rfc6455 rfc6455]] +[def __rfc7230__ [@https://tools.ietf.org/html/rfc7230 rfc7230]] +[def __asio_handler_invoke__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]] +[def __asio_handler_allocate__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`]] +[def __void_or_deduced__ [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]] -[section:intro Introduction] +[def __AsyncReadStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]] +[def __AsyncWriteStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]] +[def __CompletionHandler__ [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]] +[def __ConstBufferSequence__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]] +[def __MutableBufferSequence__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]] +[def __SyncReadStream__ [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]] +[def __SyncWriteStream__ [@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]] -Beast is a header-only, cross-platform C++ library built on Boost.Asio and -Boost, containing two modules implementing widely used network protocols. -Beast.HTTP offers a universal model for describing, sending, and receiving -HTTP messages while Beast.WebSocket provides a complete implementation of -the WebSocket protocol. Their design achieves these goals: +[def __Body__ [link beast.ref.Body [*`Body`]]] +[def __DynamicBuffer__ [link beast.ref.DynamicBuffer [*DynamicBuffer]]] +[def __FieldSequence__ [link beast.ref.FieldSequence [*FieldSequence]]] +[def __Parser__ [link beast.ref.Parser [*`Parser`]]] -* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be -used to build clients, servers, or both. - -* [*Ease of Use.] HTTP messages are modeled using simple, readily -accessible objects. Functions and classes used to send and receive HTTP -or WebSocket messages are designed to resemble Boost.Asio as closely as -possible. Users familiar with Boost.Asio will be immediately comfortable -using this library. - -* [*Flexibility.] Interfaces do not mandate specific implementation -strategies; important decisions such as buffer or thread management are -left to users of the library. - -* [*Performance.] The implementation performs competitively, making it a -realistic choice for building high performance network servers. - -* [*Scalability.] Development of network applications that scale to thousands -of concurrent connections is possible with the implementation. - -* [*Basis for further abstraction.] The interfaces facilitate the -development of other libraries that provide higher levels of abstraction. - - - -[section:requirements Requirements] - -Beast requires: - -* [*C++11.] A minimum of C++11 is needed. -* [*Boost.] Beast is built on Boost, especially Boost.Asio. -* [*OpenSSL.] If using TLS/Secure sockets (optional). - -[note Tested compilers: msvc-14+, gcc 5+, clang 3.6+] - -The library is [*header-only]. It is not necessary to add any .cpp files, -or to edit your existing build script or project file except to provide -that the include/ directory for beast is searched for include files. - -[endsect] - - - -[section:example Examples] - -These usage examples are intended to quickly impress upon readers the -flavor of the library. They are complete programs which may be built -and run. Source code and build scripts for these programs may be found -in the examples directory. - -Use HTTP to request the root page from a website and print the response: -``` -#include -#include -#include -#include - -int main() -{ - // Normal boost::asio setup - std::string const host = "boost.org"; - boost::asio::io_service ios; - boost::asio::ip::tcp::resolver r{ios}; - boost::asio::ip::tcp::socket sock{ios}; - boost::asio::connect(sock, - r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"})); - - // Send HTTP request using beast - beast::http::request_v1 req; - req.method = "GET"; - req.url = "/"; - req.version = 11; - req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port())); - req.headers.replace("User-Agent", "Beast"); - beast::http::prepare(req); - beast::http::write(sock, req); - - // Receive and print HTTP response using beast - beast::streambuf sb; - beast::http::response_v1 resp; - beast::http::read(sock, sb, resp); - std::cout << resp; -} -``` - -Establish a WebSocket connection, send a message and receive the reply: -``` -#include -#include -#include -#include -#include - -int main() -{ - // Normal boost::asio setup - std::string const host = "echo.websocket.org"; - boost::asio::io_service ios; - boost::asio::ip::tcp::resolver r{ios}; - boost::asio::ip::tcp::socket sock{ios}; - boost::asio::connect(sock, - r.resolve(boost::asio::ip::tcp::resolver::query{host, "80"})); - - // WebSocket connect and send message using beast - beast::websocket::stream ws{sock}; - ws.handshake(host, "/"); - ws.write(boost::asio::buffer("Hello, world!")); - - // Receive WebSocket message, print and close using beast - beast::streambuf sb; - beast::websocket::opcode op; - ws.read(op, sb); - ws.close(beast::websocket::close_code::normal); - std::cout << to_string(sb.data()) << "\n"; -} -``` - -[endsect] - - - -[section:credits Credits] - -Boost.Asio is the inspiration behind which all of the interfaces and -implementation strategies are built. Some parts of the documentation are -written to closely resemble the wording and presentation of Boost.Asio -documentation. Credit goes to Christopher Kohloff for the wonderful -Asio library and the ideas upon which Beast is built. - -Beast would not be possible without the considerable time and patience -contributed by David Schwartz, Edward Hennis, Howard Hinnant, Miguel Portilla, -Nikolaos Bougalis, Scott Determan, Scott Schurr, and Ripple Labs for -supporting its development. - -[endsect] - - - -[endsect] +[def __basic_fields__ [link beast.ref.http__basic_fields `basic_fields`]] +[def __fields__ [link beast.ref.http__fields `fields`]] +[def __header__ [link beast.ref.http__header `header`]] +[def __message__ [link beast.ref.http__message `message`]] +[def __streambuf__ [link beast.ref.streambuf `streambuf`]] +[def __basic_streambuf__ [link beast.ref.basic_streambuf `basic_streambuf`]] +Beast is a cross-platform, header-only C++ library built on Boost.Asio that +provides implementations of the HTTP and WebSocket protocols. +[variablelist + [[ + [link beast.overview Overview] + ][ + An introduction with features, requirements, and credits. + ]] + [[ + [link beast.http Using HTTP] + ][ + How to use Beast's HTTP interfaces in your applications. + ]] + [[ + [link beast.websocket Using WebSocket] + ][ + How to use Beast's WebSocket interfaces in your applications. + ]] + [[ + [link beast.example Examples] + ][ + Examples that illustrate the use of Beast in more complex applications. + ]] + [[ + [link beast.design Design] + ][ + Design rationale, answers to review questions, and + other library comparisons. + ]] + [[ + [link beast.ref Reference] + ][ + Detailed class and function reference. + ]] + [[ + [link beast.index Index] + ][ + Book-style text index of Beast documentation. + ]] +] +[include overview.qbk] [include http.qbk] [include websocket.qbk] +[include examples.qbk] +[include design.qbk] -[section:types Type Requirements] +[section:ref Reference] +[xinclude quickref.xml] [include types/Body.qbk] [include types/BufferSequence.qbk] [include types/DynamicBuffer.qbk] @@ -199,13 +110,7 @@ supporting its development. [include types/Reader.qbk] [include types/Streams.qbk] [include types/Writer.qbk] +[include reference.qbk] [endsect] -[include design.qbk] -[section:quickref Quick Reference] -[xinclude quickref.xml] -[endsect] -[include reference.qbk] -[section:idx Index] [xinclude index.xml] -[endsect] diff --git a/doc/overview.qbk b/doc/overview.qbk new file mode 100644 index 000000000..c0639a7c8 --- /dev/null +++ b/doc/overview.qbk @@ -0,0 +1,114 @@ +[/ + Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +] + +[section:overview Introduction] + +Beast is a header-only, cross-platform C++ library built on Boost.Asio and +parts of Boost, containing two modules implementing widely used network +protocols. Beast offers a universal HTTP message model, plus algorithms for +parsing and serializing HTTP/1 messages. Beast.WebSocket provides a complete +implementation of the WebSocket protocol. Their design achieves these goals: + +* [*Symmetry.] Interfaces are role-agnostic; the same interfaces can be +used to build clients, servers, or both. + +* [*Ease of Use.] HTTP messages are modeled using simple, readily +accessible objects. Functions and classes used to send and receive HTTP +or WebSocket messages are designed to resemble Boost.Asio as closely as +possible. Users familiar with Boost.Asio will be immediately comfortable +using this library. + +* [*Flexibility.] Interfaces do not mandate specific implementation +strategies; important decisions such as buffer or thread management are +left to users of the library. + +* [*Performance.] The implementation performs competitively, making it a +realistic choice for building high performance network servers. + +* [*Scalability.] Development of network applications that scale to thousands +of concurrent connections is possible with the implementation. + +* [*Basis for further abstraction.] The interfaces facilitate the +development of other libraries that provide higher levels of abstraction. + +The HTTP portion of Beast is designed to be a low-level building block for +creating higher level libraries. It implements only the HTTP protocol, and +does not handle domain specific features (for example: cookies, redirects, or +deflate content encodings). + +[heading Requirements] + +Beast requires: + +* [*C++11.] A minimum of C++11 is needed. +* [*Boost.] Beast is built on Boost, especially Boost.Asio. +* [*OpenSSL.] If using TLS/Secure sockets (optional). + +[note Tested compilers: msvc-14+, gcc 5+, clang 3.6+] + +The library is [*header-only]. It is not necessary to add any .cpp files, +or to add commands to your build script for building Beast. To link your +program successfully, you'll need to add the Boost.System library to link +with. If you use coroutines you'll also need the Boost.Coroutine library. +Please visit the Boost documentation for instructions on how to do this for +your particular build system. + +[heading Motivation] + +Beast is built on Boost.Asio A proposal to add networking functionality to the +C++ standard library, based on Boost.Asio, is under consideration by the +committee and on track for standardization. Since the final approved networking +interface for the C++ standard library will likely closely resemble the current +interface of Boost.Asio, the choice of Boost.Asio as the network transport +layer is prudent. + +The HTTP protocol is pervasive in network applications. As C++ is a logical +choice for high performance network servers, there is great utility in solid +building blocks for manipulating, sending, and receiving HTTP messages +compliant with the Hypertext Transfer Protocol and the supplements that +follow. Unfortunately reliable implementations or industry standards do not +exist in C++. The development of higher level libraries is stymied by the +lack of a common set of low-level algorithms and types for interacting with +the HTTP protocol. + +Today's web applications increasingly rely on alternatives to standard HTTP +to achieve performance and/or responsiveness. While WebSocket implementations +are widely available in common web development languages such as Javascript, +good implementations in C++ are scarce. A survey of existing C++ WebSocket +solutions reveals interfaces which lack symmetry, impose performance penalties, +and needlessly restrict implementation strategies. + +Beast.WebSocket takes advantage of Boost.Asio's extensible asynchronous +model, handler allocation, and handler invocation hooks. Calls to +Beast.WebSocket asynchronous initiation functions allow callers the choice +of using a completion handler, stackful or stackless coroutines, futures, +or user defined customizations (for example, Boost.Fiber). The +implementation uses handler invocation hooks (__asio_handler_invoke__), +providing execution guarantees on composed operations in a manner identical +to Boost.Asio. The implementation also uses handler allocation hooks +(__asio_handler_allocate__) when allocating memory internally for composed +operations. + +There is no need for inheritance or virtual members in a +[link beast.ref.websocket__stream `websocket::stream`]. +All operations are templated and transparent to the compiler, allowing for +maximum inlining and optimization. + +[heading Credits] + +Boost.Asio is the inspiration behind which all of the interfaces and +implementation strategies are built. Some parts of the documentation are +written to closely resemble the wording and presentation of Boost.Asio +documentation. Credit goes to Christopher Kohlhoff for the wonderful +Asio library and the ideas upon which Beast is built. + +Beast would not be possible without the considerable time and patience +contributed by David Schwartz, Edward Hennis, Howard Hinnant, Miguel Portilla, +Nikolaos Bougalis, Scott Determan, Scott Schurr, and Ripple Labs for +supporting its development. + +[endsect] diff --git a/doc/quickref.xml b/doc/quickref.xml index 729a0ad5f..3fe63b3ef 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -16,10 +16,10 @@ - + HTTP - + WebSocket @@ -30,53 +30,82 @@ Classes basic_dynabuf_body - basic_headers + basic_fields basic_parser_v1 empty_body - headers + fields + header + header_parser_v1 message + parser_v1 + request + request_header + response + response_header resume_context streambuf_body string_body - Options + rfc7230 - body_max_size - headers_max_size - skip_body - - Type Traits - - is_Body - is_Parser - is_ReadableBody - is_WritableBody + + ext_list + param_list + token_list Functions - async_parse async_read + async_parse async_write + chunk_encode + chunk_encode_final + swap + is_keep_alive + is_upgrade + operator<< parse prepare read - swap + reason_string + with_body write + Type Traits + + is_Body + is_Parser + is_Reader + is_Writer + has_reader + has_writer + + + + Options + + header_max_size + body_max_size + skip_body + Constants + body_what connection + no_content_length + parse_error + parse_flag Concepts - Body - Field - FieldSequence - Parser - Reader - Writer + Body + Field + FieldSequence + Parser + Reader + Writer @@ -88,24 +117,22 @@ reason_string teardown_tag - Options - - auto_fragment_size - decorate - keep_alive - mask_buffer_size - message_type - pong_callback - read_buffer_size - read_message_max - - - Functions async_teardown teardown + Options + + auto_fragment + decorate + keep_alive + message_type + pong_callback + read_buffer_size + read_message_max + write_buffer_size + Constants close_code @@ -121,11 +148,15 @@ + Core + + ZLib + @@ -138,9 +169,12 @@ buffers_adapter consuming_buffers dynabuf_readstream + errc + error_category error_code + error_condition handler_alloc - prepared_buffers + handler_ptr static_streambuf static_streambuf_n static_string @@ -153,18 +187,15 @@ bind_handler buffer_cat - consumed_buffers prepare_buffer prepare_buffers to_string - write Type Traits - is_AsyncReadStream is_AsyncWriteStream is_AsyncStream @@ -181,11 +212,29 @@ Concepts - AsyncStream - BufferSequence - DynamicBuffer - Stream - SyncStream + AsyncStream + BufferSequence + DynamicBuffer + Stream + SyncStream + + + + Classes + + deflate_stream + inflate_stream + z_params + + Functions + + deflate_upper_bound + + Constants + + error + Flush + Strategy diff --git a/doc/reference.xsl b/doc/reference.xsl index 4c37e3065..ffa66952c 100644 --- a/doc/reference.xsl +++ b/doc/reference.xsl @@ -31,8 +31,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:ref Reference] - - ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.return_type_of_an_initiating_function ['void-or-deduced]]`` + __void_or_deduced__ @@ -198,6 +195,18 @@ select="concat(substring-before($name, '::'), '__', substring-after($name, '::'))"/> + + + + + + + + + + - + + select="concat(substring-after($name, '~'), '_dtor_')"/> @@ -1055,10 +1064,26 @@ ] - + + [heading Static Data Members] + [table [[Name][Description]] + + + [ + [[link beast.ref. + . + [* + + ]]] [ + + ] ] + + ] + + [heading Data Members] [table [[Name][Description]] - + [ [[link beast.ref. @@ -1528,47 +1553,50 @@ - class ``[link beast.types.streams.AsyncStream [*AsyncStream]]`` + class ``[link beast.ref.streams.AsyncStream [*AsyncStream]]`` - class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncReadStream.html [*AsyncReadStream]]`` + class __AsyncReadStream__ - class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/AsyncWriteStream.html [*AsyncWriteStream]]`` + class __AsyncWriteStream__ - class ``[link beast.types.Body [*Body]]`` + class ``[link beast.ref.Body [*Body]]`` - class ``[link beast.types.BufferSequence [*BufferSequence]]`` + class ``[link beast.ref.BufferSequence [*BufferSequence]]`` - ``[link beast.types.BufferSequence [*BufferSequence]]`` + ``[link beast.ref.BufferSequence [*BufferSequence]]`` - class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/CompletionHandler.html [*CompletionHandler]]`` + class __CompletionHandler__ - class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/ConstBufferSequence.html [*ConstBufferSequence]]`` + class __ConstBufferSequence__ - class ``[link beast.types.DynamicBuffer [*DynamicBuffer]]`` + class ``[link beast.ref.DynamicBuffer [*DynamicBuffer]]`` - class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/MutableBufferSequence.html [*MutableBufferSequence]]`` + class __MutableBufferSequence__ + + + class ``[link beast.ref.Parser [*Parser]]`` - class ``[link beast.types.streams.Stream [*Stream]]`` + class ``[link beast.ref.streams.Stream [*Stream]]`` - class ``[link beast.types.streams.SyncStream [*SyncStream]]`` + class ``[link beast.ref.streams.SyncStream [*SyncStream]]`` - class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncReadStream.html [*SyncReadStream]]`` + class __SyncReadStream__ - class ``[@http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/reference/SyncWriteStream.html [*SyncWriteStream]]`` + class __SyncWriteStream__ @@ -1682,6 +1710,14 @@ ``` + + + + ``` + + ``` + + diff --git a/doc/source.dox b/doc/source.dox index 6e56005fb..624ab6331 100644 --- a/doc/source.dox +++ b/doc/source.dox @@ -107,52 +107,8 @@ INPUT = \ ../include/beast/core \ ../include/beast/http \ ../include/beast/websocket \ - ../include/beast/doc_debug.hpp \ - - ../include/beast/async_completion.hpp \ - ../include/beast/basic_streambuf.hpp \ - ../include/beast/bind_handler.hpp \ - ../include/beast/buffer_cat.hpp \ - ../include/beast/buffers_adapter.hpp \ - ../include/beast/consuming_buffers.hpp \ - ../include/beast/handler_alloc.hpp \ - ../include/beast/http.hpp \ - ../include/beast/placeholders.hpp \ - ../include/beast/prepare_buffers.hpp \ - ../include/beast/static_streambuf.hpp \ - ../include/beast/streambuf.hpp \ - ../include/beast/streambuf_readstream.hpp \ - ../include/beast/to_string.hpp \ - ../include/beast/type_check.hpp \ - ../include/beast/websocket.hpp \ - ../include/beast/write_streambuf.hpp \ - ../include/beast/http/basic_headers.hpp \ - ../include/beast/http/basic_parser_v1.hpp \ - ../include/beast/http/body_writer.hpp \ - ../include/beast/http/chunk_encode.hpp \ - ../include/beast/http/empty_body.hpp \ - ../include/beast/http/error.hpp \ - ../include/beast/http/fields.hpp \ - ../include/beast/http/headers.hpp \ - ../include/beast/http/message.hpp \ - ../include/beast/http/message_v1.hpp \ - ../include/beast/http/method.hpp \ - ../include/beast/http/parse_error.hpp \ - ../include/beast/http/parser.hpp \ - ../include/beast/http/read.hpp \ - ../include/beast/http/resume_context.hpp \ - ../include/beast/http/rfc2616.hpp \ - ../include/beast/http/streambuf_body.hpp \ - ../include/beast/http/string_body.hpp \ - ../include/beast/http/type_check.hpp \ - ../include/beast/http/write.hpp \ - ../include/beast/websocket/error.hpp \ - ../include/beast/websocket/option.hpp \ - ../include/beast/websocket/rfc6455.hpp \ - ../include/beast/websocket/ssl.hpp \ - ../include/beast/websocket/static_string.hpp \ - ../include/beast/websocket/stream.hpp \ - ../include/beast/websocket/teardown.hpp \ + ../include/beast/zlib \ + ../extras/beast/doc_debug.hpp INPUT_ENCODING = UTF-8 FILE_PATTERNS = diff --git a/doc/types/Body.qbk b/doc/types/Body.qbk index 95c91417a..41560e67e 100644 --- a/doc/types/Body.qbk +++ b/doc/types/Body.qbk @@ -5,7 +5,11 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:Body Body] +[section:Body Body requirements] + +A [*Body] type is supplied as a template argument to the __message__ class. It +controls both the type of the data member of the resulting message object, and +the algorithms used during parsing and serialization. In this table: @@ -22,17 +26,12 @@ In this table: will be not movable or not copyable. ] ] -[ - [`X:value_type{}`] - [] - [`DefaultConstructible`] -] [ [`Body::reader`] [] [ If present, a type meeting the requirements of - [link beast.types.Reader [*`Reader`]]. + [link beast.ref.Reader [*`Reader`]]. Provides an implementation to parse the body. ] ] @@ -41,7 +40,7 @@ In this table: [] [ If present, a type meeting the requirements of - [link beast.types.Writer [*`Writer`]]. + [link beast.ref.Writer [*`Writer`]]. Provides an implementation to serialize the body. ] ] diff --git a/doc/types/BufferSequence.qbk b/doc/types/BufferSequence.qbk index 04457281b..ae493f480 100644 --- a/doc/types/BufferSequence.qbk +++ b/doc/types/BufferSequence.qbk @@ -5,7 +5,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:BufferSequence BufferSequence] +[section:BufferSequence BufferSequence requirements] A `BufferSequence` is a type meeting either of the following requirements: diff --git a/doc/types/DynamicBuffer.qbk b/doc/types/DynamicBuffer.qbk index dd0243bf5..ff8c12258 100644 --- a/doc/types/DynamicBuffer.qbk +++ b/doc/types/DynamicBuffer.qbk @@ -5,7 +5,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:DynamicBuffer DynamicBuffer] +[section:DynamicBuffer DynamicBuffer requirements] A dynamic buffer encapsulates memory storage that may be automatically resized as required, where the memory is divided into an input sequence followed by an @@ -27,7 +27,7 @@ implementation strategies: * A sequence of one or more octet arrays of varying sizes. Additional octet array objects are appended to the sequence to accommodate changes in the - size of the character sequence. This is the implementation approached + size of the character sequence. This is the implementation approach currently offered by [link beast.ref.basic_streambuf `basic_streambuf`]. In the table below: @@ -88,7 +88,7 @@ In the table below: ] [ [`a.prepare(n)`] - [`X:mutable_buffers_type`] + [`X::mutable_buffers_type`] [ Returns a mutable buffer sequence u representing the output sequence, and where `buffer_size(u) == n`. The dynamic buffer reallocates memory diff --git a/doc/types/Field.qbk b/doc/types/Field.qbk index e5d8b22c6..c24925275 100644 --- a/doc/types/Field.qbk +++ b/doc/types/Field.qbk @@ -5,7 +5,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:Field Field] +[section:Field Field requirements] A [*`Field`] represents a single HTTP header field/value pair. diff --git a/doc/types/FieldSequence.qbk b/doc/types/FieldSequence.qbk index c0cd123bf..b602c32df 100644 --- a/doc/types/FieldSequence.qbk +++ b/doc/types/FieldSequence.qbk @@ -5,16 +5,17 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:FieldSequence FieldSequence] +[section:FieldSequence FieldSequence requirements] -A [*`FieldSequence`] is an iterable container whose value type meets -the requirements of [link beast.types.Field [*`Field`]]. +A [*FieldSequence] is an iterable container whose value type meets +the requirements of [link beast.ref.Field [*Field]]. Objects that meet +these requirements become serializable by the implementation. In this table: -* `X` denotes a type that meets the requirements of [*`FieldSequence`]. +* `X` denotes a type that meets the requirements of [*FieldSequence]. -* `a` is a value of type `X`. +* `c` is a value of type `X const`. [table FieldSequence requirements [[operation][type][semantics, pre/post-conditions]] @@ -22,25 +23,33 @@ In this table: [`X::value_type`] [] [ - A type that meets the requirements of `Field`. + A type that meets the requirements of [link beast.ref.Field [*Field]]. ] ] [ [`X::const_iterator`] [] [ - A type that meets the requirements of `ForwardIterator`. + An iterator type whose `reference` type meets the + requirements of [link beast.ref.Field [*Field]], and which + satisfies all the requirements of [*ForwardIterator], + except that: + + [ordered_list + [there is no requirement that `operator->` is provided, and] + [there is no requirement that `reference` be a reference type.] + ] ] ] [ - [`a.begin()`] + [`c.begin()`] [`X::const_iterator`] [ Returns an iterator to the beginning of the field sequence. ] ] [ - [`a.end()`] + [`c.end()`] [`X::const_iterator`] [ Returns an iterator to the end of the field sequence. diff --git a/doc/types/Parser.qbk b/doc/types/Parser.qbk index 0690f23f6..3bf31ca27 100644 --- a/doc/types/Parser.qbk +++ b/doc/types/Parser.qbk @@ -5,19 +5,22 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:Parser Parser] +[section:Parser Parser requirements] -A [*`Parser`] is used to deserialize HTTP/1 messages from [link beast.types.streams streams]. -Objects of this type are used with [link beast.ref.http__parse http::parse] and -[link beast.ref.http__async_parse http::async_parse]. +A [*Parser] is used to deserialize objects from +[link beast.ref.streams streams]. Objects of this type are used with +[link beast.ref.http__parse http::parse] and +[link beast.ref.http__async_parse http::async_parse]. The definition of +an object, and the predicate defining when the parse is complete, are +determined by the implementation. In this table: -* `X` denotes a type meeting the requirements of [*`Parser`]. +* `X` denotes a type meeting the requirements of [*Parser]. * `a` denotes a value of type `X`. -* `b` is a value meeting the requirements of [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/ConvertibleToConstBuffer.html [*`ConvertibleToConstBuffer`]]. +* `b` is a value meeting the requirements of __ConstBufferSequence__. * `ec` is a value of type [link beast.ref.error_code `error_code&`]. @@ -27,18 +30,18 @@ In this table: [`a.complete()`] [`bool`] [ - Returns `true` when a complete HTTP/1 message has been parsed. + Returns `true` when parsing is complete. ] ] [ [`a.write(b, ec)`] [`std::size_t`] [ - Parses the octets in the specified input buffer sequentially until - an error occurs, the end of the buffer is reached, or a complete - HTTP/1 message has been parsed. If an error occurs, `ec` is set - to the error code and parsing stops. This function returns the - number of bytes consumed from the input buffer. + Sequentially parses the octets in the specified input buffer sequence + until an error occurs, the end of the buffer is reached, or parsing is + complete. Upon success, this function returns the number of bytes used + from the input. If an error occurs, `ec` is set to the error code and + parsing stops. ] ] [ @@ -48,9 +51,9 @@ In this table: Indicates to the parser that no more octets will be available. Typically this function is called when the end of stream is reached. For example, if a call to `boost::asio::ip::tcp::socket::read_some` - generates a `boost::asio::error::eof` error. Some HTTP/1 messages - determine the end of the message body by an end of file marker or - closing of the connection. + generates a `boost::asio::error::eof` error. Some objects, such as + certain HTTP/1 messages, determine the end of the message body by + an end of file marker or closing of the connection. ] ] ] diff --git a/doc/types/Reader.qbk b/doc/types/Reader.qbk index a94db4d0b..d1952e42f 100644 --- a/doc/types/Reader.qbk +++ b/doc/types/Reader.qbk @@ -5,11 +5,11 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:Reader Reader] +[section:Reader Reader requirements] -Parser implementations will construct the corresponding `reader` object -during the parse. This customization point allows the Body to determine -the strategy for storing incoming message body data. +Parsers provided by the implementation will construct the corresponding +`reader` object during parsing. This customization point allows the +Body to determine the strategy for storing incoming message body data. In this table: @@ -17,15 +17,14 @@ In this table: * `a` denotes a value of type `X`. -* `p` is any pointer. - * `n` is a value convertible to `std::size_t`. -* `ec` is a value of type `error_code&`. +* `p` is a `void const*` to valid memory of at least `n` bytes. -* `m` denotes a value of type `message const&` where - `std::is_same:value == true` +* `ec` is a value of type [link beast.ref.error_code `error_code&`]. +* `m` denotes a value of type `message&` where + `std::is_same::value == true`. [table Reader requirements [[operation] [type] [semantics, pre/post-conditions]] @@ -33,22 +32,38 @@ In this table: [`X a(m);`] [] [ - `a` is constructible from `m`. The lifetime of `m` is - guaranteed to end no earlier than after `a` is destroyed. + `a` is constructible from `m`. The lifetime of `m` is guaranteed + to end no earlier than after `a` is destroyed. The constructor + will be called after all headers have been stored in `m`, and + before any body data is deserialized. This function must be + `noexcept`. + ] +] +[ + [`a.init(ec)`] + [`void`] + [ + Called immediately after construction. If the function sets + an error code in `ec`, the parse is aborted and the error is + propagated to the caller. This function must be `noexcept`. ] ] [ [`a.write(p, n, ec)`] [`void`] [ - Deserializes the input sequence into the body. - If `ec` is set, the deserialization is aborted and the error - is returned to the caller. + Deserializes the input sequence into the body. If `ec` is set, + the deserialization is aborted and the error is propagated to + the caller. If the message headers specify a chunked transfer + encoding, the reader will receive the decoded version of the + body. This function must be `noexcept`. ] ] ] -[note Definitions for required `Reader` member functions should be declared -inline so the generated code becomes part of the implementation. ] +[note + Definitions for required `Reader` member functions should be declared + inline so the generated code can become part of the implementation. +] [endsect] diff --git a/doc/types/Streams.qbk b/doc/types/Streams.qbk index fb0920a10..a5493600a 100644 --- a/doc/types/Streams.qbk +++ b/doc/types/Streams.qbk @@ -5,7 +5,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:streams Streams] +[section:streams Streams requirements] Stream types represent objects capable of performing synchronous or asynchronous I/O. They are based on concepts from `boost::asio`. diff --git a/doc/types/Writer.qbk b/doc/types/Writer.qbk index f27565272..32ea72273 100644 --- a/doc/types/Writer.qbk +++ b/doc/types/Writer.qbk @@ -5,7 +5,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] -[section:Writer Writer] +[section:Writer Writer requirements] A `Writer` serializes the message body. The implementation creates an instance of this type when serializing a message, and calls into it zero or more times @@ -28,13 +28,13 @@ In this table: * `m` denotes a value of type `message const&` where `std::is_same:value == true`. -* `rc` is an object of type [link beast.ref.http__resume_context resume_context]. +* `rc` is an object of type [link beast.ref.http__resume_context `resume_context`]. -* `ec` is a value of type `error_code&`. +* `ec` is a value of type [link beast.ref.error_code `error_code&`] * `wf` is a [*write function]: a function object of unspecified type provided by the implementation which accepts any value meeting the requirements - of `ConstBufferSequence` as its single parameter. + of __ConstBufferSequence__ as its single parameter. [table Writer requirements [[operation] [type] [semantics, pre/post-conditions]] @@ -42,17 +42,18 @@ In this table: [`X a(m);`] [] [ - `a` is constructible from `m`. The lifetime of `m` is - guaranteed to end no earlier than after `a` is destroyed. + `a` is constructible from `m`. The lifetime of `m` is guaranteed + to end no earlier than after `a` is destroyed. This function must + be `noexcept`. ] ] [ [`a.init(ec)`] [`void`] [ - Called immediately after construction. - If `ec` is set, the serialization is aborted and the error - is propagated to the caller. + Called immediately after construction. If the function sets an + error code in `ec`, the serialization is aborted and the error + is propagated to the caller. This function must be `noexcept`. ] ] [ @@ -67,31 +68,33 @@ In this table: the serialized message body will be sent unmodified, with the error `boost::asio::error::eof` returned to the caller, to notify they should close the connection to indicate the end of the message. + This function must be `noexcept`. ] ] [ - [`a(rc, ec, wf)`] + [`a.write(rc, ec, wf)`] [`boost::tribool`] [ - Called repeatedly after `init` succeeds. - `wf` is a function object which takes as its single parameter, - any value meeting the requirements of `ConstBufferSequence`. - Buffers provided by the `writer` to this [*write function] must - remain valid until the next member function of `writer` is + Called repeatedly after `init` succeeds. `wf` is a function object + which takes as its single parameter any value meeting the requirements + of __ConstBufferSequence__. Buffers provided to this write function + must remain valid until the next member function of `writer` is invoked (which may be the destructor). This function returns `true` - to indicate all message body data has been written, or `false` - if there is more body data. If the return value is - `boost::indeterminate`, the implementation will suspend the operation - until the writer invokes `rc`. It is the writers responsibility when - returning `boost::indeterminate`, to acquire ownership of the - `resume_context` via move construction and eventually call it or else - undefined behavior results. + to indicate all message body data has been written, or `false` if + there is more body data. If the return value is `boost::indeterminate`, + the implementation will suspend the operation until the writer invokes + `rc`. It is the writers responsibility when returning + `boost::indeterminate`, to acquire ownership of `rc` via move + construction and eventually call it or else undefined behavior + results. This function must be `noexcept`. ] ] ] -[note Definitions for required `Writer` member functions should be declared -inline so the generated code becomes part of the implementation. ] +[note + Definitions for required `Writer` member functions should be declared + inline so the generated code can become part of the implementation. +] Exemplar: ``` @@ -109,7 +112,7 @@ public: */ template explicit - writer(message const& msg); + writer(message const& msg) noexcept; /** Initialize the writer. @@ -119,7 +122,7 @@ public: @param ec Contains the error code if any errors occur. */ void - init(error_code& ec); + init(error_code& ec) noexcept; /** Returns the content length. @@ -128,8 +131,8 @@ public: use chunk-encoding or terminate the connection to indicate the end of the message. */ - std::size_t - content_length() const; + std::uint64_t + content_length() noexcept; /** Write zero or one buffer representing the message body. @@ -172,7 +175,10 @@ public: */ template boost::tribool - operator()(resume_context&&, error_code&, WriteFunction&& write); + write( + resume_context&&, + error_code&, + WriteFunction&& wf) noexcept; }; ``` diff --git a/doc/websocket.qbk b/doc/websocket.qbk index ff9c235e8..904a703c9 100644 --- a/doc/websocket.qbk +++ b/doc/websocket.qbk @@ -7,6 +7,21 @@ [section:websocket WebSocket] +[block ''' + + Creation + Making connections + Handshaking + Messages + Frames + Control Frames + Buffers + Asynchronous interface + The io_service + Thread Safety + +'''] + The WebSocket Protocol enables two-way communication between a client running untrusted code in a controlled environment to a remote host that has opted-in to communications from that code. The protocol consists of an opening @@ -22,48 +37,12 @@ C++ approach. The WebSocket protocol is described fully in [@https://tools.ietf.org/html/rfc6455 rfc6455] +[note + The following documentation assumes familiarity with both + Boost.Asio and the WebSocket protocol specification described in __rfc6455__. +] -[section:motivation Motivation] - -Today's web applications increasingly rely on alternatives to standard HTTP -to achieve performance and/or responsiveness. While WebSocket implementations -are widely available in common web development languages such as Javascript, -good implementations in C++ are scarce. A survey of existing C++ WebSocket -solutions reveals interfaces which lack symmetry, impose performance penalties, -and needlessly restrict implementation strategies. - -Beast.WebSocket is built on Boost.Asio, a robust cross platform networking -framework that is part of Boost and also offered as a standalone library. -A proposal to add networking functionality to the C++ standard library, -based on Boost.Asio, is under consideration by the standards committee. -Since the final approved networking interface for the C++ standard library -will likely closely resemble the current interface of Boost.Asio, it is -logical for Beast.WebSocket to use Boost.Asio as its network transport. - -Beast.WebSocket takes advantage of Boost.Asio's extensible asynchronous -model, handler allocation, and handler invocation hooks. Calls to -Beast.WebSocket asynchronous initiation functions allow callers the choice -of using a completion handler, stackful or stackless coroutines, futures, -or user defined customizations (for example, Boost.Fiber). The -implementation uses handler invocation hooks -([@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_invoke.html `asio_handler_invoke`]), -providing execution guarantees on composed operations in a manner -identical to Boost.Asio. The implementation also uses handler allocation hooks -([@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/asio_handler_allocate.html `asio_handler_allocate`]) -when allocating memory internally for composed operations. - -There is no need for inheritance or virtual members in a -[link beast.ref.websocket__stream `beast::websocket::stream`]. -All operations are templated and transparent to the compiler, allowing for -maximum inlining and optimization. - -[note The documentation which follows assumes familiarity with -both Boost.Asio and the WebSocket protocol specification described in -[@https://tools.ietf.org/html/rfc6455 rfc6455] ] - -[endsect] - [section:creation Creation] @@ -71,15 +50,15 @@ both Boost.Asio and the WebSocket protocol specification described in The interface to Beast's WebSocket implementation is a single template class [link beast.ref.websocket__stream `beast::websocket::stream`] which wraps a "next layer" object. The next layer object must meet the requirements -of [link beast.types.streams.SyncStream [*`SyncReadStream`]] if synchronous +of [link beast.ref.streams.SyncStream [*`SyncReadStream`]] if synchronous operations are performed, or -[link beast.types.streams.AsyncStream [*`AsyncStream`]] if asynchronous +[link beast.ref.streams.AsyncStream [*`AsyncStream`]] if asynchronous operations are performed, or both. Arguments supplied during construction are passed to next layer's constructor. Here we declare a websocket stream over a TCP/IP socket with ownership of the socket: ``` boost::asio::io_service ios; -beast::websocket::stream ws(ios); +beast::websocket::stream ws{ios}; ``` [heading Using SSL] @@ -92,8 +71,8 @@ argument when constructing the stream. #include boost::asio::io_service ios; -boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23); -beast::websocket::stream ws(ios, ctx); +boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23}; +beast::websocket::stream ws{ios, ctx}; ``` [note @@ -108,7 +87,7 @@ to wrap an object that already exists. This socket can be moved in: ``` boost::asio::ip::tcp::socket&& sock; ... - beast::websocket::stream ws(std::move(sock)); + beast::websocket::stream ws{std::move(sock)}; ``` Or, the wrapper can be constructed with a non-owning reference. In @@ -117,35 +96,37 @@ underlying socket being wrapped: ``` boost::asio::ip::tcp::socket sock; ... - beast::websocket::stream ws(sock); + beast::websocket::stream ws{sock}; ``` The layer being wrapped can be accessed through the websocket's "next layer", permitting callers to interact directly with its interface. ``` - boost::asio::ssl::context ctx(boost::asio::ssl::context::sslv23); - beast::websocket::stream> ws(ios, ctx); + boost::asio::ssl::context ctx{boost::asio::ssl::context::sslv23}; + beast::websocket::stream> ws{ios, ctx}; ... ws.next_layer().shutdown(); // ssl::stream shutdown ``` -[important Initiating read and write operations on the next layer while -websocket operations are being performed can break invariants, and -result in undefined behavior. ] +[warning + Initiating read and write operations on the next layer while + stream operations are being performed can break invariants, and + result in undefined behavior. +] [endsect] -[section:connecting Making connections] +[section:connections Making connections] Connections are established by using the interfaces which already exist for the next layer. For example, making an outgoing connection: ``` std::string const host = "mywebapp.com"; boost::asio::io_service ios; - boost::asio::ip::tcp::resolver r(ios); - beast::websocket::stream ws(ios); + boost::asio::ip::tcp::resolver r{ios}; + beast::websocket::stream ws{ios}; boost::asio::connect(ws.next_layer(), r.resolve(boost::asio::ip::tcp::resolver::query{host, "ws"})); ``` @@ -154,12 +135,14 @@ Accepting an incoming connection: ``` void do_accept(boost::asio::ip::tcp::acceptor& acceptor) { - beast::websocket::stream ws(acceptor.get_io_service()); + beast::websocket::stream ws{acceptor.get_io_service()}; acceptor.accept(ws.next_layer()); } ``` -[note Examples use synchronous interfaces for clarity of exposition. ] +[note + Examples use synchronous interfaces for clarity of exposition. +] [endsect] @@ -171,16 +154,17 @@ A WebSocket session begins when one side sends the HTTP Upgrade request for websocket, and the other side sends an appropriate HTTP response indicating that the request was accepted and that the connection has been upgraded. The HTTP Upgrade request must include the Host HTTP field, -and the URI of the resource to request. `handshake` is used to send the +and the URI of the resource to request. +[link beast.ref.websocket__stream.handshake `handshake`] is used to send the request with the required host and resource strings. ``` - beast::websocket::stream ws(ios); + beast::websocket::stream ws{ios}; ... ws.set_option(beast::websocket::keep_alive(true)); ws.handshake("ws.example.com:80", "/cgi-bin/bitcoin-prices"); ``` -The [link beast.ref.websocket__stream `beast::websocket::stream`] automatically +The [link beast.ref.websocket__stream `stream`] automatically handles receiving and processing the HTTP response to the handshake request. The call to handshake is successful if a HTTP response is received with the 101 "Switching Protocols" status code. On failure, an error is returned or an @@ -190,7 +174,7 @@ open for a subsequent handshake attempt Performing a handshake for an incoming websocket upgrade request operates similarly. If the handshake fails, an error is returned or exception thrown: ``` - beast::websocket::stream ws(ios); + beast::websocket::stream ws{ios}; ... ws.accept(); ``` @@ -205,7 +189,7 @@ void do_accept(boost::asio::ip::tcp::socket& sock) boost::asio::streambuf sb; boost::asio::read_until(sock, sb, "\r\n\r\n"); ... - beast::websocket::stream ws(sock); + beast::websocket::stream ws{sock}; ws.accept(sb.data()); ... } @@ -218,10 +202,10 @@ void do_accept(boost::asio::ip::tcp::socket& sock) { boost::asio::streambuf sb; beast::http::request request; - beast::http::read(sock, request); + beast::http::read(sock, sb, request); if(beast::http::is_upgrade(request)) { - websocket::stream ws(sock); + websocket::stream ws{sock}; ws.accept(request); ... } @@ -242,17 +226,19 @@ void echo(beast::websocket::stream& ws) { beast::streambuf sb; beast::websocket::opcode::value op; - ws.read(sb); + ws.read(op, sb); - ws.set_option(beast::websocket::message_type(op)); + ws.set_option(beast::websocket::message_type{op}); ws.write(sb.data()); sb.consume(sb.size()); } ``` -[important Calls to [link beast.ref.websocket__stream.set_option `set_option`] -must be made from the same implicit or explicit strand as that used to perform -other operations. ] +[important + Calls to [link beast.ref.websocket__stream.set_option `set_option`] + must be made from the same implicit or explicit strand as that used + to perform other operations. +] [endsect] @@ -280,9 +266,9 @@ void echo(beast::websocket::stream& ws) if(fi.fin) break; } - ws.set_option(beast::websocket::message_type(fi.op)); + ws.set_option(beast::websocket::message_type{fi.op}); beast::consuming_buffers< - beast::streambuf::const_buffers_type> cb(sb.data()); + beast::streambuf::const_buffers_type> cb{sb.data()}; for(;;) { using boost::asio::buffer_size; @@ -305,46 +291,49 @@ void echo(beast::websocket::stream& ws) -[section:controlframes Control frames] +[section:control Control Frames] -During read operations, the implementation automatically reads and processes -WebSocket control frames such as ping, pong, and close. Pings are replied -to as soon as possible, pongs are delivered to the pong callback. The receipt -of a close frame initiates the WebSocket close procedure, eventually resulting -in the error code [link beast.ref.websocket__error `error::closed`] being -delivered to the caller in a subsequent read operation, assuming no other error +Control frames are small (less than 128 bytes) messages entirely contained +in an individual WebSocket frame. They may be sent at any time by either +peer on an established connection, and can appear in between continuation +frames for a message. There are three types of control frames: ping, pong, +and close. + +A sent ping indicates a request that the sender wants to receive a pong. A +pong is a response to a ping. Pongs may be sent unsolicited, at any time. +One use for an unsolicited pong is to inform the remote peer that the +session is still active after a long period of inactivity. A close frame +indicates that the remote peer wishes to close the WebSocket connection. +The connection is considered gracefully closed when each side has sent +and received a close frame. + +During read operations, Beast automatically reads and processes control +frames. Pings are replied to as soon as possible with a pong, received +pongs are delivered to the pong callback. The receipt of a close frame +initiates the WebSocket close procedure, eventually resulting in the error +code [link beast.ref.websocket__error `error::closed`] being delivered +to the caller in a subsequent read operation, assuming no other error takes place. -To ensure timely delivery of control frames, large messages are broken up -into smaller sized frames. The implementation chooses the size and number -of the frames making up the message. The automatic fragment size option -gives callers control over the size of these frames: -``` - ... - ws.set_option(beast::websocket::auto_fragment_size(8192)); -``` +A consequence of this automatic behavior is that caller-initiated read +operations can cause socket writes. However, these writes will not +compete with caller-initiated write operations. For the purposes of +correctness with respect to the stream invariants, caller-initiated +read operations still only count as a read. This means that callers can +have a simultaneous active read and write operation in progress, while +the implementation also automatically handles control frames. -The WebSocket protocol defines a procedure and control message for initiating -a close of the session. Handling of close initiated by the remote end of the -connection is performed automatically. To manually initiate a close, use -[link beast.ref.websocket__stream.close `close`]: -``` - ws.close(); -``` +[heading Ping and Pong Frames] -[note To receive the [link beast.ref.websocket__error `error::closed`] -error, a read operation is required. ] - -[endsect] - - - -[section:pongs Pong messages] +Ping and pong messages are control frames which may be sent at any time +by either peer on an established WebSocket connection. They are sent +using the functions + [link beast.ref.websocket__stream.ping `ping`] and + [link beast.ref.websocket__stream.pong `pong`]. To receive pong control frames, callers may register a "pong callback" using -[link beast.ref.websocket__stream.set_option `set_option`]: - -the following signature: +[link beast.ref.websocket__stream.set_option `set_option`]. The object provided +with this option should be callable with the following signature: ``` void on_pong(ping_data const& payload); ... @@ -361,9 +350,47 @@ reset when a pong is received. The same callback is used for both synchronous and asynchronous reads. The pong callback is passive; in order to receive pongs, a synchronous or asynchronous stream read function must be active. -[note When an asynchronous read function receives a pong, the the pong callback -is invoked in the same manner as that used to invoke the final completion -handler of the corresponding read function.] +[note + When an asynchronous read function receives a pong, the the pong + callback is invoked in the same manner as that used to invoke the + final completion handler of the corresponding read function. +] + +[heading Close Frames] + +The WebSocket protocol defines a procedure and control message for initiating +a close of the session. Handling of close initiated by the remote end of the +connection is performed automatically. To manually initiate a close, use +the [link beast.ref.websocket__stream.close `close`] function: +``` + ws.close(); +``` + +When the remote peer initiates a close by sending a close frame, Beast +will handle it for you by causing the next read to return `error::closed`. +When this error code is delivered, it indicates to the application that +the WebSocket connection has been closed cleanly, and that the TCP/IP +connection has been closed. After initiating a close, it is necessary to +continue reading messages until receiving the error `error::closed`. This +is because the remote peer may still be sending message and control frames +before it receives and responds to the close frame. + +[important + To receive the [link beast.ref.websocket__error `error::closed`] + error, a read operation is required. +] + +[heading Auto-fragment] + +To ensure timely delivery of control frames, large messages can be broken up +into smaller sized frames. The automatic fragment option turns on this +feature, and the write buffer size option determines the maximum size of +the fragments: +``` + ... + ws.set_option(beast::websocket::auto_fragment{true}); + ws.set_option(beast::websocket::write_buffer_size{16384}); +``` [endsect] @@ -373,7 +400,7 @@ handler of the corresponding read function.] Because calls to read data may return a variable amount of bytes, the interface to calls that read data require an object that meets the requirements -of [link beast.types.DynamicBuffer [*`DynamicBuffer`]]. This concept is modeled on +of [link beast.ref.DynamicBuffer [*`DynamicBuffer`]]. This concept is modeled on [@http://www.boost.org/doc/libs/1_61_0/doc/html/boost_asio/reference/basic_streambuf.html `boost::asio::basic_streambuf`]. The implementation does not perform queueing or buffering of messages. If @@ -429,7 +456,7 @@ use or require threads. -[section:safety Thread Safety] +[section:threads Thread Safety] Like a regular asio socket, a [link beast.ref.websocket__stream `stream`] is not thread safe. Callers are responsible for synchronizing operations on the diff --git a/examples/Jamfile b/examples/Jamfile.v2 similarity index 96% rename from examples/Jamfile rename to examples/Jamfile.v2 index f9936fe81..2dd0427be 100644 --- a/examples/Jamfile +++ b/examples/Jamfile.v2 @@ -5,8 +5,6 @@ # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) # -import os ; - exe http-crawl : http_crawl.cpp urls_large_data.cpp @@ -23,4 +21,3 @@ exe http-example : exe websocket-example : websocket_example.cpp ; - diff --git a/examples/file_body.hpp b/examples/file_body.hpp index 6df8dc86d..c92d4fe7e 100644 --- a/examples/file_body.hpp +++ b/examples/file_body.hpp @@ -8,9 +8,12 @@ #ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED #define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED -#include +#include +#include +#include #include #include +#include #include #include @@ -34,8 +37,8 @@ struct file_body writer(writer const&) = delete; writer& operator=(writer const&) = delete; - template - writer(message const& m) noexcept + template + writer(message const& m) noexcept : path_(m.body) { } @@ -58,14 +61,15 @@ struct file_body } std::uint64_t - content_length() const + content_length() const noexcept { return size_; } - template + template boost::tribool - operator()(resume_context&&, error_code&, Write&& write) + write(resume_context&&, error_code&, + WriteFunction&& wf) noexcept { if(size_ - offset_ < sizeof(buf_)) buf_len_ = static_cast( @@ -75,7 +79,7 @@ struct file_body auto const nread = fread(buf_, 1, sizeof(buf_), file_); (void)nread; offset_ += buf_len_; - write(boost::asio::buffer(buf_, buf_len_)); + wf(boost::asio::buffer(buf_, buf_len_)); return offset_ >= size_; } }; diff --git a/examples/http_async_server.hpp b/examples/http_async_server.hpp index 44b808121..2c1df4b43 100644 --- a/examples/http_async_server.hpp +++ b/examples/http_async_server.hpp @@ -12,6 +12,8 @@ #include "mime_type.hpp" #include +#include +#include #include #include #include @@ -32,8 +34,8 @@ class http_async_server using address_type = boost::asio::ip::address; using socket_type = boost::asio::ip::tcp::socket; - using req_type = request_v1; - using resp_type = response_v1; + using req_type = request; + using resp_type = response; std::mutex m_; bool log_ = true; @@ -85,32 +87,26 @@ public: private: template + bool isRequest, class Body, class Fields> class write_op { - using alloc_type = - handler_alloc; - struct data { - Stream& s; - message_v1 m; - Handler h; bool cont; + Stream& s; + message m; - template - data(DeducedHandler&& h_, Stream& s_, - message_v1&& m_) - : s(s_) + data(Handler& handler, Stream& s_, + message&& m_) + : cont(beast_asio_helpers:: + is_continuation(handler)) + , s(s_) , m(std::move(m_)) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: write_op(write_op&&) = default; @@ -118,7 +114,7 @@ private: template write_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), s, std::forward(args)...)) { @@ -135,23 +131,23 @@ private: beast::http::async_write(d.s, d.m, std::move(*this)); return; } - d.h(ec); + d_.invoke(ec); } friend void* asio_handler_allocate( std::size_t size, write_op* op) { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + return beast_asio_helpers:: + allocate(size, op->d_.handler()); } friend void asio_handler_deallocate( void* p, std::size_t size, write_op* op) { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); } friend @@ -164,22 +160,22 @@ private: friend void asio_handler_invoke(Function&& f, write_op* op) { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + return beast_asio_helpers:: + invoke(f, op->d_.handler()); } }; template static void - async_write(Stream& stream, message_v1< - isRequest, Body, Headers>&& msg, + async_write(Stream& stream, message< + isRequest, Body, Fields>&& msg, DeducedHandler&& handler) { write_op::type, - isRequest, Body, Headers>{std::forward( + isRequest, Body, Fields>{std::forward( handler), stream, std::move(msg)}; } @@ -236,12 +232,12 @@ private: path = server_.root_ + path; if(! boost::filesystem::exists(path)) { - response_v1 res; + response res; res.status = 404; res.reason = "Not Found"; res.version = req_.version; - res.headers.insert("Server", "http_async_server"); - res.headers.insert("Content-Type", "text/html"); + res.fields.insert("Server", "http_async_server"); + res.fields.insert("Content-Type", "text/html"); res.body = "The file '" + path + "' was not found"; prepare(res); async_write(sock_, std::move(res), @@ -249,32 +245,35 @@ private: asio::placeholders::error)); return; } - resp_type res; - res.status = 200; - res.reason = "OK"; - res.version = req_.version; - res.headers.insert("Server", "http_async_server"); - res.headers.insert("Content-Type", mime_type(path)); - res.body = path; try { + resp_type res; + res.status = 200; + res.reason = "OK"; + res.version = req_.version; + res.fields.insert("Server", "http_async_server"); + res.fields.insert("Content-Type", mime_type(path)); + res.body = path; prepare(res); + async_write(sock_, std::move(res), + std::bind(&peer::on_write, shared_from_this(), + asio::placeholders::error)); } catch(std::exception const& e) { - res = {}; + response res; res.status = 500; res.reason = "Internal Error"; res.version = req_.version; - res.headers.insert("Server", "http_async_server"); - res.headers.insert("Content-Type", "text/html"); + res.fields.insert("Server", "http_async_server"); + res.fields.insert("Content-Type", "text/html"); res.body = std::string{"An internal error occurred"} + e.what(); prepare(res); + async_write(sock_, std::move(res), + std::bind(&peer::on_write, shared_from_this(), + asio::placeholders::error)); } - async_write(sock_, std::move(res), - std::bind(&peer::on_write, shared_from_this(), - asio::placeholders::error)); } void on_write(error_code ec) diff --git a/examples/http_crawl.cpp b/examples/http_crawl.cpp index 9948851fb..3e67a14ed 100644 --- a/examples/http_crawl.cpp +++ b/examples/http_crawl.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include using namespace beast::http; @@ -35,21 +36,21 @@ int main(int, char const*[]) ip::tcp::socket sock(ios); connect(sock, it); auto ep = sock.remote_endpoint(); - request_v1 req; + request req; req.method = "GET"; req.url = "/"; req.version = 11; - req.headers.insert("Host", host + - std::string(":") + std::to_string(ep.port())); - req.headers.insert("User-Agent", "beast/http"); + req.fields.insert("Host", host + std::string(":") + + boost::lexical_cast(ep.port())); + req.fields.insert("User-Agent", "beast/http"); prepare(req); write(sock, req); - response_v1 res; + response res; streambuf sb; beast::http::read(sock, sb, res); std::cout << res; } - catch(boost::system::system_error const& ec) + catch(beast::system_error const& ec) { std::cerr << host << ": " << ec.what(); } diff --git a/examples/http_example.cpp b/examples/http_example.cpp index 55d74a829..55910fee0 100644 --- a/examples/http_example.cpp +++ b/examples/http_example.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -21,18 +22,19 @@ int main() r.resolve(boost::asio::ip::tcp::resolver::query{host, "http"})); // Send HTTP request using beast - beast::http::request_v1 req; + beast::http::request req; req.method = "GET"; req.url = "/"; req.version = 11; - req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port())); - req.headers.replace("User-Agent", "Beast"); + req.fields.replace("Host", host + ":" + + boost::lexical_cast(sock.remote_endpoint().port())); + req.fields.replace("User-Agent", "Beast"); beast::http::prepare(req); beast::http::write(sock, req); // Receive and print HTTP response using beast beast::streambuf sb; - beast::http::response_v1 resp; + beast::http::response resp; beast::http::read(sock, sb, resp); std::cout << resp; } diff --git a/examples/http_server.cpp b/examples/http_server.cpp index 246508a8e..d21fd18ad 100644 --- a/examples/http_server.cpp +++ b/examples/http_server.cpp @@ -20,34 +20,26 @@ int main(int ac, char const* av[]) po::options_description desc("Options"); desc.add_options() - ("root,r", po::value()->implicit_value("."), + ("root,r", po::value()->default_value("."), "Set the root directory for serving files") - ("port,p", po::value()->implicit_value(8080), + ("port,p", po::value()->default_value(8080), "Set the port number for the server") - ("ip", po::value()->implicit_value("0.0.0.0"), + ("ip", po::value()->default_value("0.0.0.0"), "Set the IP address to bind to, \"0.0.0.0\" for all") - ("threads,n", po::value()->implicit_value(4), + ("threads,n", po::value()->default_value(4), "Set the number of threads to use") ("sync,s", "Launch a synchronous server") ; po::variables_map vm; po::store(po::parse_command_line(ac, av, desc), vm); - std::string root = "."; - if(vm.count("root")) - root = vm["root"].as(); + std::string root = vm["root"].as(); - std::uint16_t port = 8080; - if(vm.count("port")) - port = vm["port"].as(); + std::uint16_t port = vm["port"].as(); - std::string ip = "0.0.0.0"; - if(vm.count("ip")) - ip = vm["ip"].as(); + std::string ip = vm["ip"].as(); - std::size_t threads = 4; - if(vm.count("threads")) - threads = vm["threads"].as(); + std::size_t threads = vm["threads"].as(); bool sync = vm.count("sync") > 0; diff --git a/examples/http_sync_server.hpp b/examples/http_sync_server.hpp index 837068472..bd6df50d0 100644 --- a/examples/http_sync_server.hpp +++ b/examples/http_sync_server.hpp @@ -11,6 +11,8 @@ #include "file_body.hpp" #include "mime_type.hpp" +#include +#include #include #include #include @@ -19,6 +21,7 @@ #include #include #include +#include #include #include @@ -32,8 +35,8 @@ class http_sync_server using address_type = boost::asio::ip::address; using socket_type = boost::asio::ip::tcp::socket; - using req_type = request_v1; - using resp_type = response_v1; + using req_type = request; + using resp_type = response; bool log_ = true; std::mutex m_; @@ -161,44 +164,48 @@ private: path = root_ + path; if(! boost::filesystem::exists(path)) { - response_v1 res; + response res; res.status = 404; res.reason = "Not Found"; res.version = req.version; - res.headers.insert("Server", "http_sync_server"); - res.headers.insert("Content-Type", "text/html"); + res.fields.insert("Server", "http_sync_server"); + res.fields.insert("Content-Type", "text/html"); res.body = "The file '" + path + "' was not found"; prepare(res); write(sock, res, ec); if(ec) break; + return; } - resp_type res; - res.status = 200; - res.reason = "OK"; - res.version = req.version; - res.headers.insert("Server", "http_sync_server"); - res.headers.insert("Content-Type", mime_type(path)); - res.body = path; try { + resp_type res; + res.status = 200; + res.reason = "OK"; + res.version = req.version; + res.fields.insert("Server", "http_sync_server"); + res.fields.insert("Content-Type", mime_type(path)); + res.body = path; prepare(res); + write(sock, res, ec); + if(ec) + break; } catch(std::exception const& e) { - res = {}; + response res; res.status = 500; res.reason = "Internal Error"; res.version = req.version; - res.headers.insert("Server", "http_sync_server"); - res.headers.insert("Content-Type", "text/html"); + res.fields.insert("Server", "http_sync_server"); + res.fields.insert("Content-Type", "text/html"); res.body = - std::string{"An internal error occurred"} + e.what(); + std::string{"An internal error occurred: "} + e.what(); prepare(res); + write(sock, res, ec); + if(ec) + break; } - write(sock, res, ec); - if(ec) - break; } fail(id, ec); } diff --git a/examples/ssl/CMakeLists.txt b/examples/ssl/CMakeLists.txt new file mode 100644 index 000000000..df35e5f32 --- /dev/null +++ b/examples/ssl/CMakeLists.txt @@ -0,0 +1,32 @@ +# Part of Beast + +GroupSources(extras/beast extras) +GroupSources(include/beast beast) + +GroupSources(examples/ssl "/") + +include_directories(${OPENSSL_INCLUDE_DIR}) + +add_executable (http-ssl-example + ${BEAST_INCLUDES} + ${EXTRAS_INCLUDES} + http_ssl_example.cpp +) + +target_link_libraries(http-ssl-example ${OPENSSL_LIBRARIES}) + +if (NOT WIN32) + target_link_libraries(http-ssl-example ${Boost_LIBRARIES} Threads::Threads) +endif() + +add_executable (websocket-ssl-example + ${BEAST_INCLUDES} + ${EXTRAS_INCLUDES} + websocket_ssl_example.cpp +) + +target_link_libraries(websocket-ssl-example ${OPENSSL_LIBRARIES}) + +if (NOT WIN32) + target_link_libraries(websocket-ssl-example ${Boost_LIBRARIES} Threads::Threads) +endif() diff --git a/examples/ssl/Jamfile.v2 b/examples/ssl/Jamfile.v2 new file mode 100644 index 000000000..b35e16f23 --- /dev/null +++ b/examples/ssl/Jamfile.v2 @@ -0,0 +1,54 @@ +# +# Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +import os ; + +if [ os.name ] = SOLARIS +{ + lib socket ; + lib nsl ; +} +else if [ os.name ] = NT +{ + lib ws2_32 ; + lib mswsock ; +} +else if [ os.name ] = HPUX +{ + lib ipv6 ; +} +else if [ os.name ] = HAIKU +{ + lib network ; +} + +if [ os.name ] = NT +{ + lib ssl : : ssleay32 ; + lib crypto : : libeay32 ; +} +else +{ + lib ssl ; + lib crypto ; +} + +project + : requirements + ssl + crypto + ; + +exe http-ssl-example + : + http_ssl_example.cpp + ; + +exe websocket-ssl-example + : + websocket_ssl_example.cpp + ; diff --git a/examples/ssl/http_ssl_example.cpp b/examples/ssl/http_ssl_example.cpp new file mode 100644 index 000000000..ff6224c28 --- /dev/null +++ b/examples/ssl/http_ssl_example.cpp @@ -0,0 +1,58 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include +#include +#include +#include +#include + +int main() +{ + using boost::asio::connect; + using socket = boost::asio::ip::tcp::socket; + using resolver = boost::asio::ip::tcp::resolver; + using io_service = boost::asio::io_service; + namespace ssl = boost::asio::ssl; + + // Normal boost::asio setup + std::string const host = "github.com"; + io_service ios; + resolver r{ios}; + socket sock{ios}; + connect(sock, r.resolve(resolver::query{host, "https"})); + + // Perform SSL handshaking + ssl::context ctx{ssl::context::sslv23}; + ssl::stream stream{sock, ctx}; + stream.set_verify_mode(ssl::verify_none); + stream.handshake(ssl::stream_base::client); + + // Send HTTP request over SSL using Beast + beast::http::request req; + req.method = "GET"; + req.url = "/"; + req.version = 11; + req.fields.insert("Host", host + ":" + + boost::lexical_cast(sock.remote_endpoint().port())); + req.fields.insert("User-Agent", "Beast"); + beast::http::prepare(req); + beast::http::write(stream, req); + + // Receive and print HTTP response using Beast + beast::streambuf sb; + beast::http::response resp; + beast::http::read(stream, sb, resp); + std::cout << resp; + + // Shut down SSL on the stream + boost::system::error_code ec; + stream.shutdown(ec); + if(ec && ec != boost::asio::error::eof) + std::cout << "error: " << ec.message(); +} diff --git a/examples/ssl/websocket_ssl_example.cpp b/examples/ssl/websocket_ssl_example.cpp new file mode 100644 index 000000000..b83e045ba --- /dev/null +++ b/examples/ssl/websocket_ssl_example.cpp @@ -0,0 +1,49 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include +#include +#include +#include +#include +#include + +int main() +{ + using boost::asio::connect; + using socket = boost::asio::ip::tcp::socket; + using resolver = boost::asio::ip::tcp::resolver; + using io_service = boost::asio::io_service; + namespace ssl = boost::asio::ssl; + + // Normal boost::asio setup + std::string const host = "echo.websocket.org"; + io_service ios; + resolver r{ios}; + socket sock{ios}; + connect(sock, r.resolve(resolver::query{host, "https"})); + + // Perform SSL handshaking + using stream_type = ssl::stream; + ssl::context ctx{ssl::context::sslv23}; + stream_type stream{sock, ctx}; + stream.set_verify_mode(ssl::verify_none); + stream.handshake(ssl::stream_base::client); + + // Secure WebSocket connect and send message using Beast + beast::websocket::stream ws{stream}; + ws.handshake(host, "/"); + ws.write(boost::asio::buffer("Hello, world!")); + + // Receive Secure WebSocket message, print and close using Beast + beast::streambuf sb; + beast::websocket::opcode op; + ws.read(op, sb); + ws.close(beast::websocket::close_code::normal); + std::cout << to_string(sb.data()) << "\n"; +} diff --git a/examples/websocket_example.cpp b/examples/websocket_example.cpp index e9978d5a6..1036e92cb 100644 --- a/examples/websocket_example.cpp +++ b/examples/websocket_example.cpp @@ -24,12 +24,12 @@ int main() // WebSocket connect and send message using beast beast::websocket::stream ws{sock}; ws.handshake(host, "/"); - ws.write(boost::asio::buffer("Hello, world!")); + ws.write(boost::asio::buffer(std::string("Hello, world!"))); // Receive WebSocket message, print and close using beast beast::streambuf sb; beast::websocket::opcode op; ws.read(op, sb); ws.close(beast::websocket::close_code::normal); - std::cout << to_string(sb.data()) << "\n"; + std::cout << beast::to_string(sb.data()) << "\n"; } diff --git a/include/beast/doc_debug.hpp b/extras/beast/doc_debug.hpp similarity index 100% rename from include/beast/doc_debug.hpp rename to extras/beast/doc_debug.hpp diff --git a/extras/beast/test/fail_counter.hpp b/extras/beast/test/fail_counter.hpp index b58e1f126..aaaa7a16a 100644 --- a/extras/beast/test/fail_counter.hpp +++ b/extras/beast/test/fail_counter.hpp @@ -13,11 +13,9 @@ namespace beast { namespace test { -enum error +enum class error { - success = 0, - - fail_error + fail_error = 1 }; namespace detail { @@ -79,14 +77,15 @@ inline error_code make_error_code(error ev) { - return error_code{static_cast(ev), - detail::get_error_category()}; + return error_code{ + static_cast::type>(ev), + detail::get_error_category()}; } /** A countdown to simulated failure. On the Nth operation, the class will fail with the specified - error code, or the default error code of @ref fail_error. + error code, or the default error code of @ref error::fail_error. */ class fail_counter { @@ -102,7 +101,7 @@ public: */ explicit fail_counter(std::size_t n, - error_code ev = make_error_code(fail_error)) + error_code ev = make_error_code(error::fail_error)) : n_(n) , ec_(ev) { diff --git a/extras/beast/test/string_stream.hpp b/extras/beast/test/string_stream.hpp index fcf77aaef..a8bd0b7ed 100644 --- a/extras/beast/test/string_stream.hpp +++ b/extras/beast/test/string_stream.hpp @@ -8,6 +8,7 @@ #ifndef BEAST_TEST_STRING_STREAM_HPP #define BEAST_TEST_STRING_STREAM_HPP +#include #include #include #include diff --git a/extras/beast/unit_test/reporter.hpp b/extras/beast/unit_test/reporter.hpp index 9b771cd6d..c521fc238 100644 --- a/extras/beast/unit_test/reporter.hpp +++ b/extras/beast/unit_test/reporter.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -214,7 +215,8 @@ reporter<_>::fmtdur(typename clock_type::duration const& d) using namespace std::chrono; auto const ms = duration_cast(d); if(ms < seconds{1}) - return std::to_string(ms.count()) + "ms"; + return boost::lexical_cast( + ms.count()) + "ms"; std::stringstream ss; ss << std::fixed << std::setprecision(1) << (ms.count()/1000.) << "s"; diff --git a/extras/beast/unit_test/runner.hpp b/extras/beast/unit_test/runner.hpp index 3530c46b5..c0091c450 100644 --- a/extras/beast/unit_test/runner.hpp +++ b/extras/beast/unit_test/runner.hpp @@ -9,7 +9,7 @@ #define BEAST_UNIT_TEST_RUNNER_H_INCLUDED #include -#include +#include #include #include #include @@ -185,7 +185,7 @@ runner::run(suite_info const& s) on_suite_begin(s); s.run(*this); // Forgot to call pass or fail. - assert(cond_); + BOOST_ASSERT(cond_); on_case_end(); on_suite_end(); return failed_; @@ -239,9 +239,9 @@ runner::testcase(std::string const& name) { std::lock_guard lock(mutex_); // Name may not be empty - assert(default_ || ! name.empty()); + BOOST_ASSERT(default_ || ! name.empty()); // Forgot to call pass or fail - assert(default_ || cond_); + BOOST_ASSERT(default_ || cond_); if(! default_) on_case_end(); default_ = false; diff --git a/extras/beast/unit_test/suite.hpp b/extras/beast/unit_test/suite.hpp index ab12f1c6e..cf01ee0e1 100644 --- a/extras/beast/unit_test/suite.hpp +++ b/extras/beast/unit_test/suite.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -17,6 +18,27 @@ namespace beast { namespace unit_test { +namespace detail { + +template +static +std::string +make_reason(String const& reason, + char const* file, int line) +{ + std::string s(reason); + if(! s.empty()) + s.append(": "); + namespace fs = boost::filesystem; + s.append(fs::path{file}.filename().string()); + s.append("("); + s.append(boost::lexical_cast(line)); + s.append(")"); + return s; +} + +} // detail + class thread; enum abort_t @@ -178,11 +200,21 @@ public: /** Record a failure. - @param reason + @param reason Optional text added to the output on a failure. + + @param file The source code file where the test failed. + + @param line The source code line number where the test failed. */ + /** @{ */ + template + void + fail(String const& reason, char const* file, int line); + template void fail(std::string const& reason = ""); + /** @} */ /** Evaluate a test condition. @@ -206,25 +238,25 @@ public: bool expect(Condition const& shouldBeTrue) { - return expect(shouldBeTrue, {}); + return expect(shouldBeTrue, ""); } - template + template bool - expect(Condition const& shouldBeTrue, std::string const& reason); + expect(Condition const& shouldBeTrue, String const& reason); template bool expect(Condition const& shouldBeTrue, char const* file, int line) { - return expect(shouldBeTrue, {}, file, line); + return expect(shouldBeTrue, "", file, line); } - template + template bool expect(Condition const& shouldBeTrue, - std::string const& reason, char const* file, int line); + String const& reason, char const* file, int line); /** @} */ // @@ -402,11 +434,11 @@ operator()(runner& r) } } -template +template bool suite:: expect( - Condition const& shouldBeTrue, std::string const& reason) + Condition const& shouldBeTrue, String const& reason) { if(shouldBeTrue) { @@ -417,26 +449,18 @@ expect( return false; } -template +template bool suite:: expect(Condition const& shouldBeTrue, - std::string const& reason, char const* file, int line) + String const& reason, char const* file, int line) { if(shouldBeTrue) { pass(); return true; } - std::string s; - if(! reason.empty()) - { - s += reason; - s += " "; - } - s += boost::filesystem::path{file}.filename().string() + - "(" + std::to_string(line) + ")"; - fail(s); + fail(detail::make_reason(reason, file, line)); return false; } @@ -535,6 +559,14 @@ fail(std::string const& reason) } } +template +void +suite:: +fail(String const& reason, char const* file, int line) +{ + fail(detail::make_reason(reason, file, line)); +} + inline void suite:: @@ -583,7 +615,8 @@ run(runner& r) If the condition is false, the file and line number are reported. */ -#define BEAST_EXPECTS(cond, reason) expect(cond, reason, __FILE__, __LINE__) +#define BEAST_EXPECTS(cond, reason) ((cond) ? (pass(), true) : \ + (fail((reason), __FILE__, __LINE__), false)) #endif } // unit_test diff --git a/extras/beast/unit_test/suite_list.hpp b/extras/beast/unit_test/suite_list.hpp index 77020e922..44bb4f908 100644 --- a/extras/beast/unit_test/suite_list.hpp +++ b/extras/beast/unit_test/suite_list.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include @@ -57,13 +57,13 @@ suite_list::insert( std::string s; s = std::string(library) + "." + module + "." + name; auto const result(names_.insert(s)); - assert(result.second); // Duplicate name + BOOST_ASSERT(result.second); // Duplicate name } { auto const result(classes_.insert( std::type_index(typeid(Suite)))); - assert(result.second); // Duplicate type + BOOST_ASSERT(result.second); // Duplicate type } #endif cont().emplace(make_suite_info( diff --git a/include/beast/core.hpp b/include/beast/core.hpp index dc750eea5..a46ad0036 100644 --- a/include/beast/core.hpp +++ b/include/beast/core.hpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include diff --git a/include/beast/core/async_completion.hpp b/include/beast/core/async_completion.hpp index dc39d5caa..dd41e76e1 100644 --- a/include/beast/core/async_completion.hpp +++ b/include/beast/core/async_completion.hpp @@ -34,11 +34,11 @@ namespace beast { ... template typename async_completion::result_type + void(error_code)>::result_type async_initfn(..., CompletionHandler&& handler) { async_completion completion(handler); + void(error_code)> completion(handler); ... return completion.result.get(); } diff --git a/include/beast/core/basic_streambuf.hpp b/include/beast/core/basic_streambuf.hpp index 6aee96034..9dac4c068 100644 --- a/include/beast/core/basic_streambuf.hpp +++ b/include/beast/core/basic_streambuf.hpp @@ -25,7 +25,7 @@ namespace beast { the sequence to accommodate changes in the size of the character sequence. - @note Meets the requirements of @b `DynamicBuffer`. + @note Meets the requirements of @b DynamicBuffer. @tparam Allocator The allocator to use for managing memory. */ @@ -209,6 +209,36 @@ public: return this->member(); } + /** Returns the default allocation size. + + This is the smallest size that the stream buffer will allocate. + The size of the allocation can influence capacity, which will + affect algorithms that use capacity to efficiently read from + streams. + */ + std::size_t + alloc_size() const + { + return alloc_size_; + } + + /** Set the default allocation size. + + This is the smallest size that the stream buffer will allocate. + The size of the allocation can influence capacity, which will + affect algorithms that use capacity to efficiently read from + streams. + + @note This will not affect any already-existing allocations. + + @param n The number of bytes. + */ + void + alloc_size(std::size_t n) + { + alloc_size_ = n; + } + /// Returns the size of the input sequence. size_type size() const @@ -220,7 +250,7 @@ public: size_type max_size() const { - return std::numeric_limits::max(); + return (std::numeric_limits::max)(); } /// Returns the maximum sum of the sizes of the input sequence and output sequence the buffer can hold without requiring reallocation. diff --git a/include/beast/core/buffer_cat.hpp b/include/beast/core/buffer_cat.hpp index dee9c3c8b..d8c24b44e 100644 --- a/include/beast/core/buffer_cat.hpp +++ b/include/beast/core/buffer_cat.hpp @@ -19,18 +19,21 @@ namespace beast { -/** Concatenate 2 or more buffer sequences to form a `ConstBufferSequence`. +/** Concatenate 2 or more buffer sequences. - This function returns a @b `ConstBufferSequence` that when iterated, - efficiently concatenates the input buffer sequences. Copies of the - arguments passed will be made; however, the returned object does - not take ownership of the underlying memory. The application is still - responsible for managing the lifetime of the referenced memory. + This function returns a constant or mutable buffer sequence which, + when iterated, efficiently concatenates the input buffer sequences. + Copies of the arguments passed will be made; however, the returned + object does not take ownership of the underlying memory. The application + is still responsible for managing the lifetime of the referenced memory. @param buffers The list of buffer sequences to concatenate. - @return A new @b `ConstBufferSequence` that represents the - concatenation of the input buffer sequences. + @return A new buffer sequence that represents the concatenation of + the input buffer sequences. This buffer sequence will be a + @b MutableBufferSequence if each of the passed buffer sequences is + also a @b MutableBufferSequence, else the returned buffer sequence + will be a @b ConstBufferSequence. */ #if GENERATING_DOCS template @@ -38,14 +41,15 @@ implementation_defined buffer_cat(BufferSequence const&... buffers) #else template -detail::buffer_cat_helper< - boost::asio::const_buffer, B1, B2, Bn...> +detail::buffer_cat_helper buffer_cat(B1 const& b1, B2 const& b2, Bn const&... bn) #endif { + static_assert( + detail::is_all_ConstBufferSequence::value, + "BufferSequence requirements not met"); return detail::buffer_cat_helper< - boost::asio::const_buffer, - B1, B2, Bn...>(b1, b2, bn...); + B1, B2, Bn...>{b1, b2, bn...}; } } // beast diff --git a/include/beast/core/consuming_buffers.hpp b/include/beast/core/consuming_buffers.hpp index a467e1712..87c3b8416 100644 --- a/include/beast/core/consuming_buffers.hpp +++ b/include/beast/core/consuming_buffers.hpp @@ -37,20 +37,12 @@ namespace beast { consumable `ConstBufferSequence`. Violations of buffer const safety are not permitted, and will result in a compile error. */ -template +template class consuming_buffers { using iter_type = typename BufferSequence::const_iterator; - static_assert(is_BufferSequence::value, - "BufferSequence requirements not met"); - - static_assert(std::is_constructible::value_type>::value, - "ValueType requirements not met"); - BufferSequence bs_; iter_type begin_; std::size_t skip_ = 0; @@ -65,7 +57,12 @@ class consuming_buffers public: /// The type for each element in the list of buffers. - using value_type = ValueType; + using value_type = typename std::conditional< + std::is_convertible::value_type, + boost::asio::mutable_buffer>::value, + boost::asio::mutable_buffer, + boost::asio::const_buffer>::type; #if GENERATING_DOCS /// A bidirectional iterator type that may be used to read elements. @@ -100,7 +97,7 @@ public: const_iterator begin() const; - /// Get a bidirectional iterator for one past the last element. + /// Get a bidirectional iterator to one past the last element. const_iterator end() const; @@ -114,25 +111,6 @@ public: consume(std::size_t n); }; -/** Returns a new, consumed buffer sequence. - - This function returns a new buffer sequence which when iterated, - efficiently represents the portion of the original buffer sequence - with `n` bytes removed from the beginning. - - Copies will be made of the buffer sequence passed, but ownership - of the underlying memory is not transferred. - - @param buffers The buffer sequence to consume. - - @param n The number of bytes to remove from the front. If this is - larger than the size of the buffer sequence, an empty buffer sequence - is returned. -*/ -template -consuming_buffers -consumed_buffers(BufferSequence const& buffers, std::size_t n); - } // beast #include diff --git a/include/beast/core/detail/bind_handler.hpp b/include/beast/core/detail/bind_handler.hpp index 6b540c281..f53b1efa4 100644 --- a/include/beast/core/detail/bind_handler.hpp +++ b/include/beast/core/detail/bind_handler.hpp @@ -8,10 +8,8 @@ #ifndef BEAST_BIND_DETAIL_HANDLER_HPP #define BEAST_BIND_DETAIL_HANDLER_HPP +#include #include -#include -#include -#include #include namespace beast { @@ -69,7 +67,7 @@ public: asio_handler_allocate( std::size_t size, bound_handler* h) { - return boost_asio_handler_alloc_helpers:: + return beast_asio_helpers:: allocate(size, h->h_); } @@ -78,7 +76,7 @@ public: asio_handler_deallocate( void* p, std::size_t size, bound_handler* h) { - boost_asio_handler_alloc_helpers:: + beast_asio_helpers:: deallocate(p, size, h->h_); } @@ -86,7 +84,7 @@ public: bool asio_handler_is_continuation(bound_handler* h) { - return boost_asio_handler_cont_helpers:: + return beast_asio_helpers:: is_continuation (h->h_); } @@ -95,7 +93,7 @@ public: void asio_handler_invoke(F&& f, bound_handler* h) { - boost_asio_handler_invoke_helpers:: + beast_asio_helpers:: invoke(f, h->h_); } }; diff --git a/include/beast/core/detail/buffer_cat.hpp b/include/beast/core/detail/buffer_cat.hpp index 65ca22144..fdf2b6104 100644 --- a/include/beast/core/detail/buffer_cat.hpp +++ b/include/beast/core/detail/buffer_cat.hpp @@ -8,6 +8,8 @@ #ifndef BEAST_DETAIL_BUFFER_CAT_HPP #define BEAST_DETAIL_BUFFER_CAT_HPP +#include +#include #include #include #include @@ -19,24 +21,36 @@ namespace beast { namespace detail { -template +template +struct common_buffers_type +{ + using type = typename std::conditional< + std::is_convertible, + typename repeat_tuple::type>::value, + boost::asio::mutable_buffer, + boost::asio::const_buffer>::type; +}; + +template class buffer_cat_helper { - std::tuple bs_; + std::tuple bn_; public: - using value_type = ValueType; + using value_type = typename + common_buffers_type::type; class const_iterator; buffer_cat_helper(buffer_cat_helper&&) = default; buffer_cat_helper(buffer_cat_helper const&) = default; - buffer_cat_helper& operator=(buffer_cat_helper&&) = default; - buffer_cat_helper& operator=(buffer_cat_helper const&) = default; + buffer_cat_helper& operator=(buffer_cat_helper&&) = delete; + buffer_cat_helper& operator=(buffer_cat_helper const&) = delete; explicit - buffer_cat_helper(Bs const&... bs) - : bs_(bs...) + buffer_cat_helper(Bn const&... bn) + : bn_(bn...) { } @@ -47,39 +61,22 @@ public: end() const; }; -template -std::size_t constexpr -max_sizeof() -{ - return sizeof(U); -} - -template -std::size_t constexpr -max_sizeof() -{ - return - max_sizeof() > max_sizeof() ? - max_sizeof() : max_sizeof(); -} - -template -class buffer_cat_helper< - ValueType, Bs...>::const_iterator +template +class buffer_cat_helper::const_iterator { std::size_t n_; - std::tuple const* bs_; + std::tuple const* bn_; std::array()> buf_; + max_sizeof()> buf_; - friend class buffer_cat_helper; + friend class buffer_cat_helper; template using C = std::integral_constant; template using iter_t = typename std::tuple_element< - I, std::tuple>::type::const_iterator; + I, std::tuple>::type::const_iterator; template iter_t& @@ -98,7 +95,8 @@ class buffer_cat_helper< } public: - using value_type = ValueType; + using value_type = typename + common_buffers_type::type; using pointer = value_type const*; using reference = value_type; using difference_type = std::ptrdiff_t; @@ -151,39 +149,39 @@ public: private: const_iterator( - std::tuple const& bs, bool at_end); + std::tuple const& bn, bool at_end); void - construct(C) + construct(C const&) { - auto constexpr I = sizeof...(Bs); + auto constexpr I = sizeof...(Bn); n_ = I; } template void - construct(C) + construct(C const&) { - if(std::get(*bs_).begin() != - std::get(*bs_).end()) + if(std::get(*bn_).begin() != + std::get(*bn_).end()) { n_ = I; new(buf_.data()) iter_t{ - std::get(*bs_).begin()}; + std::get(*bn_).begin()}; return; } construct(C{}); } void - destroy(C) + destroy(C const&) { return; } template void - destroy(C) + destroy(C const&) { if(n_ == I) { @@ -195,13 +193,15 @@ private: } void - move(C, const_iterator&&) + move(const_iterator&&, + C const&) { } template void - move(C, const_iterator&& other) + move(const_iterator&& other, + C const&) { if(n_ == I) { @@ -209,17 +209,19 @@ private: std::move(other.iter())}; return; } - move(C{}, std::move(other)); + move(std::move(other), C{}); } void - copy(C, const_iterator const&) + copy(const_iterator const&, + C const&) { } template void - copy(C, const_iterator const& other) + copy(const_iterator const& other, + C const&) { if(n_ == I) { @@ -227,35 +229,36 @@ private: other.iter()}; return; } - copy(C{}, other); + copy(other, C{}); } bool - equal(C, - const_iterator const&) const + equal(const_iterator const&, + C const&) const { return true; } template bool - equal(C, const_iterator const& other) const + equal(const_iterator const& other, + C const&) const { if(n_ == I) return iter() == other.iter(); - return equal(C{}, other); + return equal(other, C{}); } [[noreturn]] reference - dereference(C) const + dereference(C const&) const { throw std::logic_error("invalid iterator"); } template reference - dereference(C) const + dereference(C const&) const { if(n_ == I) return *iter(); @@ -264,19 +267,19 @@ private: [[noreturn]] void - increment(C) + increment(C const&) { throw std::logic_error("invalid iterator"); } template void - increment(C) + increment(C const&) { if(n_ == I) { if(++iter() != - std::get(*bs_).end()) + std::get(*bn_).end()) return; using Iter = iter_t; iter().~Iter(); @@ -286,23 +289,23 @@ private: } void - decrement(C) + decrement(C const&) { - auto constexpr I = sizeof...(Bs); + auto constexpr I = sizeof...(Bn); if(n_ == I) { --n_; new(buf_.data()) iter_t{ - std::get(*bs_).end()}; + std::get(*bn_).end()}; } decrement(C{}); } void - decrement(C<0>) + decrement(C<0> const&) { auto constexpr I = 0; - if(iter() != std::get(*bs_).begin()) + if(iter() != std::get(*bn_).begin()) { --iter(); return; @@ -312,11 +315,11 @@ private: template void - decrement(C) + decrement(C const&) { if(n_ == I) { - if(iter() != std::get(*bs_).begin()) + if(iter() != std::get(*bn_).begin()) { --iter(); return; @@ -325,7 +328,7 @@ private: using Iter = iter_t; iter().~Iter(); new(buf_.data()) iter_t{ - std::get(*bs_).end()}; + std::get(*bn_).end()}; } decrement(C{}); } @@ -333,54 +336,54 @@ private: //------------------------------------------------------------------------------ -template -buffer_cat_helper:: +template +buffer_cat_helper:: const_iterator::~const_iterator() { destroy(C<0>{}); } -template -buffer_cat_helper:: +template +buffer_cat_helper:: const_iterator::const_iterator() - : n_(sizeof...(Bs)) - , bs_(nullptr) + : n_(sizeof...(Bn)) + , bn_(nullptr) { } -template -buffer_cat_helper:: +template +buffer_cat_helper:: const_iterator::const_iterator( - std::tuple const& bs, bool at_end) - : bs_(&bs) + std::tuple const& bn, bool at_end) + : bn_(&bn) { if(at_end) - n_ = sizeof...(Bs); + n_ = sizeof...(Bn); else construct(C<0>{}); } -template -buffer_cat_helper:: +template +buffer_cat_helper:: const_iterator::const_iterator(const_iterator&& other) : n_(other.n_) - , bs_(other.bs_) + , bn_(other.bn_) { - move(C<0>{}, std::move(other)); + move(std::move(other), C<0>{}); } -template -buffer_cat_helper:: +template +buffer_cat_helper:: const_iterator::const_iterator(const_iterator const& other) : n_(other.n_) - , bs_(other.bs_) + , bn_(other.bn_) { - copy(C<0>{}, other); + copy(other, C<0>{}); } -template +template auto -buffer_cat_helper:: +buffer_cat_helper:: const_iterator::operator=(const_iterator&& other) -> const_iterator& { @@ -388,14 +391,14 @@ const_iterator::operator=(const_iterator&& other) -> return *this; destroy(C<0>{}); n_ = other.n_; - bs_ = other.bs_; - move(C<0>{}, std::move(other)); + bn_ = other.bn_; + move(std::move(other), C<0>{}); return *this; } -template +template auto -buffer_cat_helper:: +buffer_cat_helper:: const_iterator::operator=(const_iterator const& other) -> const_iterator& { @@ -403,35 +406,35 @@ const_iterator& return *this; destroy(C<0>{}); n_ = other.n_; - bs_ = other.bs_; - copy(C<0>{}, other); + bn_ = other.bn_; + copy(other, C<0>{}); return *this; } -template +template bool -buffer_cat_helper:: +buffer_cat_helper:: const_iterator::operator==(const_iterator const& other) const { - if(bs_ != other.bs_) + if(bn_ != other.bn_) return false; if(n_ != other.n_) return false; - return equal(C<0>{}, other); + return equal(other, C<0>{}); } -template +template auto -buffer_cat_helper:: +buffer_cat_helper:: const_iterator::operator*() const -> reference { return dereference(C<0>{}); } -template +template auto -buffer_cat_helper:: +buffer_cat_helper:: const_iterator::operator++() -> const_iterator& { @@ -439,30 +442,32 @@ const_iterator::operator++() -> return *this; } -template +template auto -buffer_cat_helper:: +buffer_cat_helper:: const_iterator::operator--() -> const_iterator& { - decrement(C{}); + decrement(C{}); return *this; } -template +template +inline auto -buffer_cat_helper::begin() const -> +buffer_cat_helper::begin() const -> const_iterator { - return const_iterator(bs_, false); + return const_iterator{bn_, false}; } -template +template +inline auto -buffer_cat_helper::end() const -> +buffer_cat_helper::end() const -> const_iterator { - return const_iterator(bs_, true); + return const_iterator{bn_, true}; } } // detail diff --git a/include/beast/core/detail/buffer_concepts.hpp b/include/beast/core/detail/buffer_concepts.hpp index 2361e678a..6a4ef13d6 100644 --- a/include/beast/core/detail/buffer_concepts.hpp +++ b/include/beast/core/detail/buffer_concepts.hpp @@ -85,53 +85,93 @@ public: type3::value && type4::value>; }; +template +struct is_all_ConstBufferSequence + : std::integral_constant::type::value && + is_all_ConstBufferSequence::value> +{ +}; + +template +struct is_all_ConstBufferSequence + : is_BufferSequence::type +{ +}; + template class is_DynamicBuffer { - template().prepare(1)), - boost::asio::mutable_buffer>::type::value>> + // size() + template().size()), std::size_t>> static R check1(int); template static std::false_type check1(...); using type1 = decltype(check1(0)); - template().data()), - boost::asio::const_buffer>::type::value>> + // max_size() + template().max_size()), std::size_t>> static R check2(int); template static std::false_type check2(...); using type2 = decltype(check2(0)); - template().commit(1), std::true_type{})> + // capacity() + template().capacity()), std::size_t>> static R check3(int); template static std::false_type check3(...); using type3 = decltype(check3(0)); - template().consume(1), std::true_type{})> + // data() + template().data()), + boost::asio::const_buffer>::type::value>> static R check4(int); template static std::false_type check4(...); using type4 = decltype(check4(0)); - template().size()), std::size_t>> + // prepare() + template().prepare(1)), + boost::asio::mutable_buffer>::type::value>> static R check5(int); template static std::false_type check5(...); using type5 = decltype(check5(0)); + // commit() + template().commit(1), std::true_type{})> + static R check6(int); + template + static std::false_type check6(...); + using type6 = decltype(check6(0)); + + // consume + template().consume(1), std::true_type{})> + static R check7(int); + template + static std::false_type check7(...); + using type7 = decltype(check7(0)); + public: using type = std::integral_constant; + type1::value + && type2::value + //&& type3::value // Networking TS + && type4::value + && type5::value + && type6::value + && type7::value + >; }; } // detail diff --git a/include/beast/core/detail/clamp.hpp b/include/beast/core/detail/clamp.hpp new file mode 100644 index 000000000..7c158da10 --- /dev/null +++ b/include/beast/core/detail/clamp.hpp @@ -0,0 +1,40 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_CORE_DETAIL_CLAMP_HPP +#define BEAST_CORE_DETAIL_CLAMP_HPP + +#include +#include + +namespace beast { +namespace detail { + +template +static +std::size_t +clamp(UInt x) +{ + if(x >= (std::numeric_limits::max)()) + return (std::numeric_limits::max)(); + return static_cast(x); +} + +template +static +std::size_t +clamp(UInt x, std::size_t limit) +{ + if(x >= limit) + return limit; + return static_cast(x); +} + +} // detail +} // beast + +#endif diff --git a/include/beast/core/detail/is_call_possible.hpp b/include/beast/core/detail/is_call_possible.hpp index 076c9ce22..247eb48f2 100644 --- a/include/beast/core/detail/is_call_possible.hpp +++ b/include/beast/core/detail/is_call_possible.hpp @@ -61,6 +61,8 @@ struct is_call_possible_udt3 int operator()(int); }; +#ifndef __INTELLISENSE__ +// VFALCO Fails to compile with Intellisense static_assert(is_call_possible< is_call_possible_udt1, void(int)>::value, ""); @@ -81,6 +83,7 @@ static_assert(is_call_possible< static_assert(! is_call_possible< is_call_possible_udt3 const, int(int)>::value, ""); +#endif } // test diff --git a/include/beast/core/impl/prepare_buffers.ipp b/include/beast/core/detail/prepare_buffers.hpp similarity index 52% rename from include/beast/core/impl/prepare_buffers.ipp rename to include/beast/core/detail/prepare_buffers.hpp index 1bf469bce..129417e68 100644 --- a/include/beast/core/impl/prepare_buffers.ipp +++ b/include/beast/core/detail/prepare_buffers.hpp @@ -5,38 +5,104 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_IMPL_PREPARE_BUFFERS_IPP -#define BEAST_IMPL_PREPARE_BUFFERS_IPP +#ifndef BEAST_DETAIL_PREPARED_BUFFERS_HPP +#define BEAST_DETAIL_PREPARED_BUFFERS_HPP +#include #include #include #include #include #include +#include #include namespace beast { +namespace detail { +/** A buffer sequence adapter that shortens the sequence size. + + The class adapts a buffer sequence to efficiently represent + a shorter subset of the original list of buffers starting + with the first byte of the original sequence. + + @tparam BufferSequence The buffer sequence to adapt. +*/ template -void -prepared_buffers:: -setup(std::size_t n) +class prepared_buffers { - for(end_ = bs_.begin(); end_ != bs_.end(); ++end_) + using iter_type = + typename BufferSequence::const_iterator; + + BufferSequence bs_; + iter_type back_; + iter_type end_; + std::size_t size_; + + template + prepared_buffers(Deduced&& other, + std::size_t nback, std::size_t nend) + : bs_(std::forward(other).bs_) + , back_(std::next(bs_.begin(), nback)) + , end_(std::next(bs_.begin(), nend)) + , size_(other.size_) { - auto const len = - boost::asio::buffer_size(*end_); - if(n <= len) - { - size_ = n; - back_ = end_++; - return; - } - n -= len; } - size_ = 0; - back_ = end_; -} + + void + setup(std::size_t n); + +public: + /// The type for each element in the list of buffers. + using value_type = typename std::conditional< + std::is_convertible::value_type, + boost::asio::mutable_buffer>::value, + boost::asio::mutable_buffer, + boost::asio::const_buffer>::type; + +#if GENERATING_DOCS + /// A bidirectional iterator type that may be used to read elements. + using const_iterator = implementation_defined; + +#else + class const_iterator; + +#endif + + /// Move constructor. + prepared_buffers(prepared_buffers&&); + + /// Copy constructor. + prepared_buffers(prepared_buffers const&); + + /// Move assignment. + prepared_buffers& operator=(prepared_buffers&&); + + /// Copy assignment. + prepared_buffers& operator=(prepared_buffers const&); + + /** Construct a shortened buffer sequence. + + @param n The maximum number of bytes in the wrapped + sequence. If this is larger than the size of passed, + buffers, the resulting sequence will represent the + entire input sequence. + + @param buffers The buffer sequence to adapt. A copy of + the sequence will be made, but ownership of the underlying + memory is not transferred. + */ + prepared_buffers(std::size_t n, BufferSequence const& buffers); + + /// Get a bidirectional iterator to the first element. + const_iterator + begin() const; + + /// Get a bidirectional iterator to one past the last element. + const_iterator + end() const; +}; template class prepared_buffers::const_iterator @@ -50,8 +116,12 @@ class prepared_buffers::const_iterator typename BufferSequence::const_iterator it_; public: - using value_type = - typename std::iterator_traits::value_type; + using value_type = typename std::conditional< + std::is_convertible::value_type, + boost::asio::mutable_buffer>::value, + boost::asio::mutable_buffer, + boost::asio::const_buffer>::type; using pointer = value_type const*; using reference = value_type; using difference_type = std::ptrdiff_t; @@ -59,10 +129,10 @@ public: std::bidirectional_iterator_tag; const_iterator() = default; - const_iterator(const_iterator&& other) = default; - const_iterator(const_iterator const& other) = default; - const_iterator& operator=(const_iterator&& other) = default; - const_iterator& operator=(const_iterator const& other) = default; + const_iterator(const_iterator&& other); + const_iterator(const_iterator const& other); + const_iterator& operator=(const_iterator&& other); + const_iterator& operator=(const_iterator const& other); bool operator==(const_iterator const& other) const @@ -126,6 +196,67 @@ private: } }; +template +void +prepared_buffers:: +setup(std::size_t n) +{ + for(end_ = bs_.begin(); end_ != bs_.end(); ++end_) + { + auto const len = + boost::asio::buffer_size(*end_); + if(n <= len) + { + size_ = n; + back_ = end_++; + return; + } + n -= len; + } + size_ = 0; + back_ = end_; +} + +template +prepared_buffers::const_iterator:: +const_iterator(const_iterator&& other) + : b_(other.b_) + , it_(std::move(other.it_)) +{ +} + +template +prepared_buffers::const_iterator:: +const_iterator(const_iterator const& other) + : b_(other.b_) + , it_(other.it_) +{ +} + +template +auto +prepared_buffers::const_iterator:: +operator=(const_iterator&& other) -> + const_iterator& +{ + b_ = other.b_; + it_ = std::move(other.it_); + return *this; +} + +template +auto +prepared_buffers::const_iterator:: +operator=(const_iterator const& other) -> + const_iterator& +{ + if(&other == this) + return *this; + b_ = other.b_; + it_ = other.it_; + return *this; +} + template prepared_buffers:: prepared_buffers(prepared_buffers&& other) @@ -187,6 +318,7 @@ prepared_buffers(std::size_t n, BufferSequence const& bs) } template +inline auto prepared_buffers::begin() const -> const_iterator @@ -195,6 +327,7 @@ prepared_buffers::begin() const -> } template +inline auto prepared_buffers::end() const -> const_iterator @@ -202,14 +335,7 @@ prepared_buffers::end() const -> return const_iterator{*this, true}; } -template -inline -prepared_buffers -prepare_buffers(std::size_t n, BufferSequence const& buffers) -{ - return prepared_buffers(n, buffers); -} - +} // detail } // beast #endif diff --git a/include/beast/core/detail/sha1.hpp b/include/beast/core/detail/sha1.hpp index 4aa83037a..28a744ec2 100644 --- a/include/beast/core/detail/sha1.hpp +++ b/include/beast/core/detail/sha1.hpp @@ -249,7 +249,7 @@ update(sha1_context& ctx, std::uint8_t const*>(message); for(;;) { - auto const n = std::min( + auto const n = (std::min)( size, sizeof(ctx.buf) - ctx.buflen); std::memcpy(ctx.buf + ctx.buflen, p, n); ctx.buflen += n; diff --git a/include/beast/core/detail/stream_concepts.hpp b/include/beast/core/detail/stream_concepts.hpp index b71557f66..7dcf0806f 100644 --- a/include/beast/core/detail/stream_concepts.hpp +++ b/include/beast/core/detail/stream_concepts.hpp @@ -9,8 +9,8 @@ #define BEAST_DETAIL_STREAM_CONCEPTS_HPP #include +#include #include -#include #include #include @@ -22,7 +22,7 @@ namespace detail { struct StreamHandler { StreamHandler(StreamHandler const&) = default; - void operator()(boost::system::error_code ec, std::size_t); + void operator()(error_code ec, std::size_t); }; using ReadHandler = StreamHandler; using WriteHandler = StreamHandler; @@ -79,9 +79,6 @@ public: template class is_SyncReadStream { - using error_code = - boost::system::error_code; - template().read_some( std::declval())), @@ -108,9 +105,6 @@ public: template class is_SyncWriteStream { - using error_code = - boost::system::error_code; - template().write_some( std::declval())), diff --git a/include/beast/core/detail/sync_ostream.hpp b/include/beast/core/detail/sync_ostream.hpp new file mode 100644 index 000000000..2d5b9e82e --- /dev/null +++ b/include/beast/core/detail/sync_ostream.hpp @@ -0,0 +1,93 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_DETAIL_SYNC_OSTREAM_HPP +#define BEAST_DETAIL_SYNC_OSTREAM_HPP + +#include +#include +#include +#include + +namespace beast { +namespace detail { + +/** A SyncWriteStream which outputs to a `std::ostream` + + Objects of this type meet the requirements of @b SyncWriteStream. +*/ +class sync_ostream +{ + std::ostream& os_; + +public: + /** Construct the stream. + + @param os The associated `std::ostream`. All buffers + written will be passed to the associated output stream. + */ + sync_ostream(std::ostream& os) + : os_(os) + { + } + + template + std::size_t + write_some(ConstBufferSequence const& buffers); + + template + std::size_t + write_some(ConstBufferSequence const& buffers, + error_code& ec); +}; + +template +std::size_t +sync_ostream:: +write_some(ConstBufferSequence const& buffers) +{ + static_assert( + is_ConstBufferSequence::value, + "ConstBufferSequence requirements not met"); + error_code ec; + auto const n = write_some(buffers, ec); + if(ec) + throw system_error{ec}; + return n; +} + +template +std::size_t +sync_ostream:: +write_some(ConstBufferSequence const& buffers, + error_code& ec) +{ + static_assert( + is_ConstBufferSequence::value, + "ConstBufferSequence requirements not met"); + std::size_t n = 0; + using boost::asio::buffer_cast; + using boost::asio::buffer_size; + for(auto const& buffer : buffers) + { + os_.write(buffer_cast(buffer), + buffer_size(buffer)); + if(os_.fail()) + { + ec = errc::make_error_code( + errc::no_stream_resources); + break; + } + n += buffer_size(buffer); + } + return n; +} + +} // detail +} // beast + +#endif diff --git a/include/beast/core/detail/type_traits.hpp b/include/beast/core/detail/type_traits.hpp new file mode 100644 index 000000000..24928abdd --- /dev/null +++ b/include/beast/core/detail/type_traits.hpp @@ -0,0 +1,84 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_DETAIL_TYPE_TRAITS_HPP +#define BEAST_DETAIL_TYPE_TRAITS_HPP + +#include +#include + +namespace beast { +namespace detail { + +template +struct make_void +{ + using type = void; +}; + +template +using void_t = typename make_void::type; + +template +inline +void +ignore_unused(Ts const& ...) +{ +} + +template +inline +void +ignore_unused() +{} + +template +std::size_t constexpr +max_sizeof() +{ + return sizeof(U); +} + +template +std::size_t constexpr +max_sizeof() +{ + return + max_sizeof() > max_sizeof() ? + max_sizeof() : max_sizeof(); +} + +template +struct repeat_tuple_impl +{ + using type = typename repeat_tuple_impl< + N - 1, T, T, Tn...>::type; +}; + +template +struct repeat_tuple_impl<0, T, Tn...> +{ + using type = std::tuple; +}; + +template +struct repeat_tuple +{ + using type = + typename repeat_tuple_impl::type; +}; + +template +struct repeat_tuple<0, T> +{ + using type = std::tuple<>; +}; + +} // detail +} // beast + +#endif diff --git a/include/beast/core/dynabuf_readstream.hpp b/include/beast/core/dynabuf_readstream.hpp index be7465f4f..32c545cc2 100644 --- a/include/beast/core/dynabuf_readstream.hpp +++ b/include/beast/core/dynabuf_readstream.hpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -47,7 +46,7 @@ namespace beast { Example: @code - // Process the next HTTP headers on the stream, + // Process the next HTTP header on the stream, // leaving excess bytes behind for the next call. // template @@ -55,7 +54,7 @@ namespace beast { dynabuf_readstream& stream) { // Read up to and including the end of the HTTP - // headers, leaving the sequence in the stream's + // header, leaving the sequence in the stream's // buffer. read_until may read past the end of the // headers; the return value will include only the // part up to the end of the delimiter. diff --git a/include/beast/core/error.hpp b/include/beast/core/error.hpp index db7b65b44..d5dc92be0 100644 --- a/include/beast/core/error.hpp +++ b/include/beast/core/error.hpp @@ -19,6 +19,18 @@ using error_code = boost::system::error_code; /// The type of system error thrown by the library using system_error = boost::system::system_error; +/// The type of error category used by the library +using error_category = boost::system::error_category; + +/// The type of error condition used by the library +using error_condition = boost::system::error_condition; + +/// The set of constants used for cross-platform error codes +#if GENERATING_DOCS +enum errc{}; +#else +namespace errc = boost::system::errc; +#endif } // beast #endif diff --git a/include/beast/core/handler_alloc.hpp b/include/beast/core/handler_alloc.hpp index 50fc0929f..814fee318 100644 --- a/include/beast/core/handler_alloc.hpp +++ b/include/beast/core/handler_alloc.hpp @@ -8,7 +8,7 @@ #ifndef BEAST_HANDLER_ALLOC_HPP #define BEAST_HANDLER_ALLOC_HPP -#include +#include #include #include #include @@ -23,15 +23,15 @@ namespace beast { This allocator uses the handler customizations `asio_handler_allocate` and `asio_handler_deallocate` to manage memory. It meets the requirements - of `Allocator` and can be used anywhere a `std::allocator` is + of @b Allocator and can be used anywhere a `std::allocator` is accepted. @tparam T The type of objects allocated by the allocator. @tparam CompletionHandler The type of handler. - @note Allocated memory is only valid until the handler is called. The - caller is still responsible for freeing memory. + @note Memory allocated by this allocator must be freed before + the handler is invoked or undefined behavior results. */ #if GENERATING_DOCS template @@ -49,12 +49,18 @@ private: template friend class handler_alloc; - CompletionHandler h_; + CompletionHandler& h_; public: using value_type = T; using is_always_equal = std::true_type; + template + struct rebind + { + using other = handler_alloc; + }; + handler_alloc() = delete; handler_alloc(handler_alloc&&) = default; handler_alloc(handler_alloc const&) = default; @@ -63,31 +69,16 @@ public: /** Construct the allocator. - The handler is moved or copied into the allocator. + A reference of the handler is stored. The handler must + remain valid for at least the lifetime of the allocator. */ explicit - handler_alloc(CompletionHandler&& h) - : h_(std::move(h)) - { - } - - /** Construct the allocator. - - A copy of the handler is made. - */ - explicit - handler_alloc(CompletionHandler const& h) + handler_alloc(CompletionHandler& h) : h_(h) { } - template - handler_alloc( - handler_alloc&& other) - : h_(std::move(other.h_)) - { - } - + /// Copy constructor template handler_alloc( handler_alloc const& other) @@ -100,7 +91,7 @@ public: { auto const size = n * sizeof(T); return static_cast( - boost_asio_handler_alloc_helpers::allocate( + beast_asio_helpers::allocate( size, h_)); } @@ -108,7 +99,7 @@ public: deallocate(value_type* p, std::ptrdiff_t n) { auto const size = n * sizeof(T); - boost_asio_handler_alloc_helpers::deallocate( + beast_asio_helpers::deallocate( p, size, h_); } diff --git a/include/beast/core/handler_helpers.hpp b/include/beast/core/handler_helpers.hpp new file mode 100644 index 000000000..ee3f7979b --- /dev/null +++ b/include/beast/core/handler_helpers.hpp @@ -0,0 +1,104 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_HANDLER_HELPERS_HPP +#define BEAST_HANDLER_HELPERS_HPP + +#include +#include +#include +#include + +/* Calls to: + + * asio_handler_allocate + * asio_handler_deallocate + * asio_handler_invoke + * asio_handler_is_continuation + + must be made from a namespace that does not + contain overloads of this function. The beast_asio_helpers + namespace is defined here for that purpose. +*/ + +namespace beast_asio_helpers { + +/// Allocation function for handlers. +template +inline +void* +allocate(std::size_t s, Handler& handler) +{ +#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) + return ::operator new(s); +#else + using boost::asio::asio_handler_allocate; + return asio_handler_allocate(s, std::addressof(handler)); +#endif +} + +/// Deallocation function for handlers. +template +inline +void +deallocate(void* p, std::size_t s, Handler& handler) +{ +#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) + ::operator delete(p); +#else + using boost::asio::asio_handler_deallocate; + asio_handler_deallocate(p, s, std::addressof(handler)); +#endif +} + +/// Invoke function for handlers. +template +inline +void +invoke(Function& function, Handler& handler) +{ +#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) + Function tmp(function); + tmp(); +#else + using boost::asio::asio_handler_invoke; + asio_handler_invoke(function, std::addressof(handler)); +#endif +} + +/// Invoke function for handlers. +template +inline +void +invoke(Function const& function, Handler& handler) +{ +#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) + Function tmp(function); + tmp(); +#else + using boost::asio::asio_handler_invoke; + asio_handler_invoke(function, std::addressof(handler)); +#endif +} + +/// Returns true if handler represents a continuation of the asynchronous operation +template +inline +bool +is_continuation(Handler& handler) +{ +#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS) + return false; +#else + using boost::asio::asio_handler_is_continuation; + return asio_handler_is_continuation(std::addressof(handler)); +#endif +} + +} // beast_asio_helpers + +#endif diff --git a/include/beast/core/handler_ptr.hpp b/include/beast/core/handler_ptr.hpp new file mode 100644 index 000000000..175be8bbd --- /dev/null +++ b/include/beast/core/handler_ptr.hpp @@ -0,0 +1,173 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_HANDLER_PTR_HPP +#define BEAST_HANDLER_PTR_HPP + +#include +#include +#include +#include + +namespace beast { + +/** A smart pointer container. + + This is a smart pointer that retains shared ownership of an + object through a pointer. Memory is managed using the allocation + and deallocation functions associated with a completion handler, + which is also stored in the object. The object is destroyed and + its memory deallocated when one of the following happens: + + @li The function @ref invoke is called. + + @li The function @ref release_handler is called + + @li The last remaining container owning the object is destroyed + + Objects of this type are used in the implementation of + composed operations. Typically the composed operation's shared + state is managed by the @ref handler_ptr and an allocator + associated with the final handler is used to create the managed + object. + + @note The reference count is stored using a 16 bit unsigned + integer. Making more than 2^16 copies of one object results + in undefined behavior. +*/ +template +class handler_ptr +{ + struct P + { + T* t; + std::atomic n; + + // There's no way to put the handler anywhere else + // without exposing ourselves to race conditions + // and all sorts of ugliness. + // See: + // https://github.com/vinniefalco/Beast/issues/215 + Handler handler; + + template + P(DeducedHandler&& handler, Args&&... args); + }; + + P* p_; + + template + handler_ptr(int, DeducedHandler&& handler, Args&&... args); + +public: + /// The type of handler this object stores + using handler_type = Handler; + + /// Copy assignment (disallowed). + handler_ptr& operator=(handler_ptr const&) = delete; + + /** Destructs the owned object if no more @ref handler_ptr link to it. + + If `*this` owns an object and it is the last @ref handler_ptr + owning it, the object is destroyed and the memory deallocated + using the associated deallocator. + */ + ~handler_ptr(); + + /** Move constructor. + + When this call returns, the moved-from container + will have no owned object. + */ + handler_ptr(handler_ptr&& other); + + /// Copy constructor + handler_ptr(handler_ptr const& other); + + /// Returns a reference to the handler + handler_type& + handler() const + { + return p_->handler; + } + + /// Returns a pointer to the owned object + T* + get() const + { + return p_->t; + } + + /// Return a reference to the owned object. + T& + operator*() const + { + return *get(); + } + + /// Return a pointer to the owned object. + T* + operator->() const + { + return get(); + } + + /** Release ownership of the handler + + If `*this` owns an object, it is first destroyed. + + @return The released handler. + */ + handler_type + release_handler(); + + /** Invoke the handler in the owned object. + + This function invokes the handler in the owned object + with a forwarded argument list. Before the invocation, + the owned object is destroyed, satisfying the + deallocation-before-invocation Asio guarantee. All + instances of @ref handler_ptr which refer to the + same owned object will be reset, including this instance. + */ + template + void + invoke(Args&&... args); + + // VFALCO The free function interface works around + // a horrible Visual Studio 15 Update 3 bug + + /** Construct a new `handler_ptr`. + + @param handler The handler. The allocator associated with + the handler will be used to allocate memory for the owned + object. This argument will be forwarded to the owned object's + constructor. + + @param args Optional arguments forwarded to + the owned object's constructor. + */ + /** @{ */ + template + friend + handler_ptr + make_handler_ptr( + CompletionHandler&& handler, Args&&... args); + + template + friend + handler_ptr + make_handler_ptr( + CompletionHandler const& handler, Args&&... args); + /** @} */ +}; + +} // beast + +#include + +#endif diff --git a/include/beast/core/impl/basic_streambuf.ipp b/include/beast/core/impl/basic_streambuf.ipp index 50bb43e02..c70d646bb 100644 --- a/include/beast/core/impl/basic_streambuf.ipp +++ b/include/beast/core/impl/basic_streambuf.ipp @@ -8,9 +8,10 @@ #ifndef BEAST_IMPL_BASIC_STREAMBUF_IPP #define BEAST_IMPL_BASIC_STREAMBUF_IPP +#include #include +#include #include -#include #include #include #include @@ -533,7 +534,7 @@ basic_streambuf::capacity() const { auto pos = out_; if(pos == list_.end()) - return 0; + return in_size_; auto n = pos->size() - out_pos_; while(++pos != list_.end()) n += pos->size(); @@ -656,7 +657,7 @@ basic_streambuf::commit(size_type n) debug_check(); } - n = std::min(n, out_end_ - out_pos_); + n = (std::min)(n, out_end_ - out_pos_); out_pos_ += n; in_size_ += n; if(out_pos_ == out_->size()) @@ -786,6 +787,7 @@ void basic_streambuf:: copy_assign(basic_streambuf const& other, std::false_type) { + beast::detail::ignore_unused(other); } template @@ -816,36 +818,36 @@ basic_streambuf::debug_check() const { #ifndef NDEBUG using boost::asio::buffer_size; - assert(buffer_size(data()) == in_size_); + BOOST_ASSERT(buffer_size(data()) == in_size_); if(list_.empty()) { - assert(in_pos_ == 0); - assert(in_size_ == 0); - assert(out_pos_ == 0); - assert(out_end_ == 0); - assert(out_ == list_.end()); + BOOST_ASSERT(in_pos_ == 0); + BOOST_ASSERT(in_size_ == 0); + BOOST_ASSERT(out_pos_ == 0); + BOOST_ASSERT(out_end_ == 0); + BOOST_ASSERT(out_ == list_.end()); return; } auto const& front = list_.front(); - assert(in_pos_ < front.size()); + BOOST_ASSERT(in_pos_ < front.size()); if(out_ == list_.end()) { - assert(out_pos_ == 0); - assert(out_end_ == 0); + BOOST_ASSERT(out_pos_ == 0); + BOOST_ASSERT(out_end_ == 0); } else { auto const& out = *out_; auto const& back = list_.back(); - assert(out_end_ <= back.size()); - assert(out_pos_ < out.size()); - assert(&out != &front || out_pos_ >= in_pos_); - assert(&out != &front || out_pos_ - in_pos_ == in_size_); - assert(&out != &back || out_pos_ <= out_end_); + BOOST_ASSERT(out_end_ <= back.size()); + BOOST_ASSERT(out_pos_ < out.size()); + BOOST_ASSERT(&out != &front || out_pos_ >= in_pos_); + BOOST_ASSERT(&out != &front || out_pos_ - in_pos_ == in_size_); + BOOST_ASSERT(&out != &back || out_pos_ <= out_end_); } #endif } @@ -855,11 +857,18 @@ std::size_t read_size_helper(basic_streambuf< Allocator> const& streambuf, std::size_t max_size) { + BOOST_ASSERT(max_size >= 1); + // If we already have an allocated + // buffer, try to fill that up first auto const avail = streambuf.capacity() - streambuf.size(); - if(avail == 0) - return std::min(max_size, - std::max(512, streambuf.alloc_size_)); - return std::min(max_size, avail); + if (avail > 0) + return (std::min)(avail, max_size); + // Try to have just one new block allocated + constexpr std::size_t low = 512; + if (streambuf.alloc_size_ > low) + return (std::min)(max_size, streambuf.alloc_size_); + // ...but enforce a 512 byte minimum. + return (std::min)(max_size, low); } template diff --git a/include/beast/core/impl/buffers_adapter.ipp b/include/beast/core/impl/buffers_adapter.ipp index d7dc132a1..cf537d6e4 100644 --- a/include/beast/core/impl/buffers_adapter.ipp +++ b/include/beast/core/impl/buffers_adapter.ipp @@ -444,7 +444,7 @@ buffers_adapter::commit(std::size_t n) max_size_ -= avail; } - n = std::min(n, out_end_ - out_pos_); + n = (std::min)(n, out_end_ - out_pos_); out_pos_ += n; in_size_ += n; max_size_ -= n; diff --git a/include/beast/core/impl/consuming_buffers.ipp b/include/beast/core/impl/consuming_buffers.ipp index 37c69005e..dcfca362b 100644 --- a/include/beast/core/impl/consuming_buffers.ipp +++ b/include/beast/core/impl/consuming_buffers.ipp @@ -18,10 +18,10 @@ namespace beast { -template -class consuming_buffers::const_iterator +template +class consuming_buffers::const_iterator { - friend class consuming_buffers; + friend class consuming_buffers; using iter_type = typename BufferSequence::const_iterator; @@ -30,8 +30,12 @@ class consuming_buffers::const_iterator consuming_buffers const* b_ = nullptr; public: - using value_type = - typename std::iterator_traits::value_type; + using value_type = typename std::conditional< + std::is_convertible::value_type, + boost::asio::mutable_buffer>::value, + boost::asio::mutable_buffer, + boost::asio::const_buffer>::type; using pointer = value_type const*; using reference = value_type; using difference_type = std::ptrdiff_t; @@ -59,8 +63,9 @@ public: reference operator*() const { - return it_ == b_->begin_ ? - *it_ + b_->skip_ : *it_; + return it_ == b_->begin_ + ? value_type{*it_} + b_->skip_ + : *it_; } pointer @@ -105,8 +110,8 @@ private: } }; -template -consuming_buffers:: +template +consuming_buffers:: consuming_buffers(consuming_buffers&& other) : consuming_buffers(std::move(other), std::distance( @@ -114,8 +119,8 @@ consuming_buffers(consuming_buffers&& other) { } -template -consuming_buffers:: +template +consuming_buffers:: consuming_buffers(consuming_buffers const& other) : consuming_buffers(other, std::distance( @@ -123,9 +128,9 @@ consuming_buffers(consuming_buffers const& other) { } -template +template auto -consuming_buffers:: +consuming_buffers:: operator=(consuming_buffers&& other) -> consuming_buffers& { @@ -137,9 +142,9 @@ operator=(consuming_buffers&& other) -> return *this; } -template +template auto -consuming_buffers:: +consuming_buffers:: operator=(consuming_buffers const& other) -> consuming_buffers& { @@ -151,35 +156,41 @@ operator=(consuming_buffers const& other) -> return *this; } -template -consuming_buffers:: +template +consuming_buffers:: consuming_buffers(BufferSequence const& bs) : bs_(bs) , begin_(bs_.begin()) { - static_assert(is_BufferSequence::value, - "BufferSequence requirements not met"); + static_assert( + is_BufferSequence::value, + "BufferSequence requirements not met"); } -template +template +inline auto -consuming_buffers::begin() const -> +consuming_buffers:: +begin() const -> const_iterator { return const_iterator{*this, begin_}; } -template +template +inline auto -consuming_buffers::end() const -> +consuming_buffers:: +end() const -> const_iterator { return const_iterator{*this, bs_.end()}; } -template +template void -consuming_buffers::consume(std::size_t n) +consuming_buffers:: +consume(std::size_t n) { using boost::asio::buffer_size; for(;n > 0 && begin_ != bs_.end(); ++begin_) @@ -196,15 +207,6 @@ consuming_buffers::consume(std::size_t n) } } -template -consuming_buffers -consumed_buffers(BufferSequence const& bs, std::size_t n) -{ - consuming_buffers cb(bs); - cb.consume(n); - return cb; -} - } // beast #endif diff --git a/include/beast/core/impl/dynabuf_readstream.ipp b/include/beast/core/impl/dynabuf_readstream.ipp index 73e75afc7..bcd7a0a51 100644 --- a/include/beast/core/impl/dynabuf_readstream.ipp +++ b/include/beast/core/impl/dynabuf_readstream.ipp @@ -9,10 +9,10 @@ #define BEAST_IMPL_DYNABUF_READSTREAM_HPP #include +#include #include -#include -#include -#include +#include +#include namespace beast { @@ -21,28 +21,22 @@ template class dynabuf_readstream< Stream, DynamicBuffer>::read_some_op { - using alloc_type = - handler_alloc; - + // VFALCO What about bool cont for is_continuation? struct data { dynabuf_readstream& srs; MutableBufferSequence bs; - Handler h; int state = 0; - template - data(DeducedHandler&& h_, - dynabuf_readstream& srs_, + data(Handler&, dynabuf_readstream& srs_, MutableBufferSequence const& bs_) : srs(srs_) , bs(bs_) - , h(std::forward(h_)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: read_some_op(read_some_op&&) = default; @@ -51,7 +45,7 @@ public: template read_some_op(DeducedHandler&& h, dynabuf_readstream& srs, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), srs, std::forward(args)...)) { @@ -66,31 +60,31 @@ public: void* asio_handler_allocate( std::size_t size, read_some_op* op) { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + return beast_asio_helpers:: + allocate(size, op->d_.handler()); } friend void asio_handler_deallocate( void* p, std::size_t size, read_some_op* op) { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); } friend bool asio_handler_is_continuation(read_some_op* op) { - return boost_asio_handler_cont_helpers:: - is_continuation(op->d_->h); + return beast_asio_helpers:: + is_continuation(op->d_.handler()); } template friend void asio_handler_invoke(Function&& f, read_some_op* op) { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + return beast_asio_helpers:: + invoke(f, op->d_.handler()); } }; @@ -150,7 +144,7 @@ read_some_op::operator()( break; } } - d.h(ec, bytes_transferred); + d_.invoke(ec, bytes_transferred); } //------------------------------------------------------------------------------ diff --git a/include/beast/core/impl/handler_ptr.ipp b/include/beast/core/impl/handler_ptr.ipp new file mode 100644 index 000000000..0f57a24d3 --- /dev/null +++ b/include/beast/core/impl/handler_ptr.ipp @@ -0,0 +1,138 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_IMPL_HANDLER_PTR_HPP +#define BEAST_IMPL_HANDLER_PTR_HPP + +#include +#include +#include +#include + +namespace beast { + +template +template +inline +handler_ptr::P:: +P(DeducedHandler&& h, Args&&... args) + : n(1) + , handler(std::forward(h)) +{ + t = reinterpret_cast( + beast_asio_helpers:: + allocate(sizeof(T), handler)); + try + { + t = new(t) T{handler, + std::forward(args)...}; + } + catch(...) + { + beast_asio_helpers:: + deallocate(t, sizeof(T), handler); + throw; + } +} + +template +template +handler_ptr:: +handler_ptr(int, DeducedHandler&& handler, Args&&... args) + : p_(new P(std::forward(handler), + std::forward(args)...)) +{ +} + +template +handler_ptr:: +~handler_ptr() +{ + if(! p_) + return; + if(--p_->n) + return; + if(p_->t) + { + p_->t->~T(); + beast_asio_helpers:: + deallocate(p_->t, sizeof(T), p_->handler); + } + delete p_; +} + +template +handler_ptr:: +handler_ptr(handler_ptr&& other) + : p_(other.p_) +{ + other.p_ = nullptr; +} + +template +handler_ptr:: +handler_ptr(handler_ptr const& other) + : p_(other.p_) +{ + if(p_) + ++p_->n; +} + +template +auto +handler_ptr:: +release_handler() -> + handler_type +{ + BOOST_ASSERT(p_); + BOOST_ASSERT(p_->t); + p_->t->~T(); + beast_asio_helpers:: + deallocate(p_->t, sizeof(T), p_->handler); + p_->t = nullptr; + return std::move(p_->handler); +} + +template +template +void +handler_ptr:: +invoke(Args&&... args) +{ + BOOST_ASSERT(p_); + BOOST_ASSERT(p_->t); + p_->t->~T(); + beast_asio_helpers:: + deallocate(p_->t, sizeof(T), p_->handler); + p_->t = nullptr; + p_->handler(std::forward(args)...); +} + +template< + class T, class CompletionHandler, class... Args> +handler_ptr +make_handler_ptr( + CompletionHandler&& handler, Args&&... args) +{ + return handler_ptr{0, + std::move(handler), + std::forward(args)...}; +} + +template< + class T, class CompletionHandler, class... Args> +handler_ptr +make_handler_ptr( + CompletionHandler const& handler, Args&&... args) +{ + return handler_ptr{0, + handler, std::forward(args)...}; +} + +} // beast + +#endif diff --git a/include/beast/core/impl/static_streambuf.ipp b/include/beast/core/impl/static_streambuf.ipp index ab487fab5..3f19cd7e1 100644 --- a/include/beast/core/impl/static_streambuf.ipp +++ b/include/beast/core/impl/static_streambuf.ipp @@ -279,6 +279,16 @@ static_streambuf::mutable_buffers_type::end() const -> //------------------------------------------------------------------------------ + +inline +auto +static_streambuf::data() const -> + const_buffers_type +{ + return const_buffers_type{in_, + static_cast(out_ - in_)}; +} + inline auto static_streambuf::prepare(std::size_t n) -> @@ -290,15 +300,6 @@ static_streambuf::prepare(std::size_t n) -> return mutable_buffers_type{out_, n}; } -inline -auto -static_streambuf::data() const -> - const_buffers_type -{ - return const_buffers_type{in_, - static_cast(out_ - in_)}; -} - } // beast #endif diff --git a/include/beast/core/prepare_buffer.hpp b/include/beast/core/prepare_buffer.hpp new file mode 100644 index 000000000..315ea3964 --- /dev/null +++ b/include/beast/core/prepare_buffer.hpp @@ -0,0 +1,68 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_PREPARE_BUFFER_HPP +#define BEAST_PREPARE_BUFFER_HPP + +#include +#include + +namespace beast { + +/** Return a shortened buffer. + + The returned buffer points to the same memory as the + passed buffer, but with a size that is equal to or less + than the size of the original buffer. + + @param n The size of the returned buffer. + + @param buffer The buffer to shorten. Ownership of the + underlying memory is not transferred. + + @return A new buffer that points to the first `n` bytes + of the original buffer. +*/ +inline +boost::asio::const_buffer +prepare_buffer(std::size_t n, + boost::asio::const_buffer buffer) +{ + using boost::asio::buffer_cast; + using boost::asio::buffer_size; + return { buffer_cast(buffer), + (std::min)(n, buffer_size(buffer)) }; +} + +/** Return a shortened buffer. + + The returned buffer points to the same memory as the + passed buffer, but with a size that is equal to or less + than the size of the original buffer. + + @param n The size of the returned buffer. + + @param buffer The buffer to shorten. Ownership of the + underlying memory is not transferred. + + @return A new buffer that points to the first `n` bytes + of the original buffer. +*/ +inline +boost::asio::mutable_buffer +prepare_buffer(std::size_t n, + boost::asio::mutable_buffer buffer) +{ + using boost::asio::buffer_cast; + using boost::asio::buffer_size; + return { buffer_cast(buffer), + (std::min)(n, buffer_size(buffer)) }; +} + +} // beast + +#endif diff --git a/include/beast/core/prepare_buffers.hpp b/include/beast/core/prepare_buffers.hpp index 9b113ae39..971725fee 100644 --- a/include/beast/core/prepare_buffers.hpp +++ b/include/beast/core/prepare_buffers.hpp @@ -8,150 +8,45 @@ #ifndef BEAST_PREPARE_BUFFERS_HPP #define BEAST_PREPARE_BUFFERS_HPP +#include #include #include #include #include #include +#include #include namespace beast { -/** Get a trimmed const buffer. +/** Return a shortened buffer sequence. - The new buffer starts at the beginning of the passed - buffer. Ownership of the underlying memory is not - transferred. -*/ -inline -boost::asio::const_buffer -prepare_buffer(std::size_t n, - boost::asio::const_buffer buffer) -{ - using boost::asio::buffer_cast; - using boost::asio::buffer_size; - return { buffer_cast(buffer), - std::min(n, buffer_size(buffer)) }; -} + This function returns a new buffer sequence which adapts the + passed buffer sequence and efficiently presents a shorter subset + of the original list of buffers starting with the first byte of + the original sequence. -/** Get a trimmed mutable buffer. + @param n The maximum number of bytes in the wrapped + sequence. If this is larger than the size of passed, + buffers, the resulting sequence will represent the + entire input sequence. - The new buffer starts at the beginning of the passed - buffer. Ownership of the underlying memory is not - transferred. -*/ -inline -boost::asio::mutable_buffer -prepare_buffer(std::size_t n, - boost::asio::mutable_buffer buffer) -{ - using boost::asio::buffer_cast; - using boost::asio::buffer_size; - return { buffer_cast(buffer), - std::min(n, buffer_size(buffer)) }; -} - -/** Wrapper to produce a trimmed buffer sequence. - - This wraps a buffer sequence to efficiently present a shorter - subset of the original list of buffers starting with the first - byte of the original sequence. - - @tparam BufferSequence The buffer sequence to wrap. + @param buffers The buffer sequence to adapt. A copy of + the sequence will be made, but ownership of the underlying + memory is not transferred. */ template -class prepared_buffers -{ - using iter_type = - typename BufferSequence::const_iterator; - - BufferSequence bs_; - iter_type back_; - iter_type end_; - std::size_t size_; - - template - prepared_buffers(Deduced&& other, - std::size_t nback, std::size_t nend) - : bs_(std::forward(other).bs_) - , back_(std::next(bs_.begin(), nback)) - , end_(std::next(bs_.begin(), nend)) - , size_(other.size_) - { - } - -public: - /// The type for each element in the list of buffers. - using value_type = - typename std::iterator_traits::value_type; - #if GENERATING_DOCS - /// A bidirectional iterator type that may be used to read elements. - using const_iterator = implementation_defined; - +implementation_defined #else - class const_iterator; - +inline +detail::prepared_buffers #endif - - /// Move constructor. - prepared_buffers(prepared_buffers&&); - - /// Copy constructor. - prepared_buffers(prepared_buffers const&); - - /// Move assignment. - prepared_buffers& operator=(prepared_buffers&&); - - /// Copy assignment. - prepared_buffers& operator=(prepared_buffers const&); - - /** Construct a wrapped buffer sequence. - - @param n The maximum number of bytes in the wrapped sequence. - If this is larger than the size of buffers, the wrapped - sequence will represent the entire input sequence. - - @param buffers The buffer sequence to wrap. A copy of the sequence - will be made, but ownership of the underlying memory is not transferred. - */ - prepared_buffers(std::size_t n, BufferSequence const& buffers); - - /// Get a bidirectional iterator to the first element. - const_iterator - begin() const; - - /// Get a bidirectional iterator for one past the last element. - const_iterator - end() const; - -private: - void - setup(std::size_t n); -}; - -//------------------------------------------------------------------------------ - -/** Return a trimmed, wrapped buffer sequence. - - This function returns a new buffer sequence which wraps the provided - buffer sequence and efficiently presents a shorter subset of the - original list of buffers starting with the first byte of the original - sequence. - - @param n The maximum number of bytes in the wrapped sequence. If this - is larger than the size of buffers, the wrapped sequence will represent - the entire input sequence. - - @param buffers The buffer sequence to wrap. A copy of the sequence - will be made, but ownership of the underlying memory is not transferred. -*/ -template -prepared_buffers -prepare_buffers(std::size_t n, BufferSequence const& buffers); +prepare_buffers(std::size_t n, BufferSequence const& buffers) +{ + return detail::prepared_buffers(n, buffers); +} } // beast -#include - #endif diff --git a/include/beast/core/static_streambuf.hpp b/include/beast/core/static_streambuf.hpp index eb1f6c9cc..2323b3baa 100644 --- a/include/beast/core/static_streambuf.hpp +++ b/include/beast/core/static_streambuf.hpp @@ -32,6 +32,7 @@ private: #else protected: #endif + std::uint8_t* begin_; std::uint8_t* in_; std::uint8_t* out_; std::uint8_t* last_; @@ -57,21 +58,35 @@ public: #endif - /// Returns the largest size output sequence possible. - std::size_t - max_size() const - { - return end_ - in_; - } - - /// Get the size of the input sequence. + /// Return the size of the input sequence. std::size_t size() const { return out_ - in_; } - /** Get a list of buffers that represents the output sequence, with the given size. + /// Return the maximum sum of the input and output sequence sizes. + std::size_t + max_size() const + { + return end_ - begin_; + } + + /// Return the maximum sum of input and output sizes that can be held without an allocation. + std::size_t + capacity() const + { + return end_ - in_; + } + + /** Get a list of buffers that represent the input sequence. + + @note These buffers remain valid across subsequent calls to `prepare`. + */ + const_buffers_type + data() const; + + /** Get a list of buffers that represent the output sequence, with the given size. @throws std::length_error if the size would exceed the limit imposed by the underlying mutable buffer sequence. @@ -93,13 +108,6 @@ public: out_ += std::min(n, last_ - out_); } - /** Get a list of buffers that represents the input sequence. - - @note These buffers remain valid across subsequent calls to `prepare`. - */ - const_buffers_type - data() const; - /// Remove bytes from the input sequence. void consume(std::size_t n) @@ -120,6 +128,7 @@ protected: void reset(std::uint8_t* p, std::size_t n) { + begin_ = p; in_ = p; out_ = p; last_ = p; diff --git a/include/beast/http.hpp b/include/beast/http.hpp index f3ffefa55..ee475791b 100644 --- a/include/beast/http.hpp +++ b/include/beast/http.hpp @@ -8,13 +8,13 @@ #ifndef BEAST_HTTP_HPP #define BEAST_HTTP_HPP -#include +#include #include -#include +#include #include -#include +#include #include -#include +#include #include #include #include diff --git a/include/beast/http/basic_dynabuf_body.hpp b/include/beast/http/basic_dynabuf_body.hpp index ee84ca538..de2f43cde 100644 --- a/include/beast/http/basic_dynabuf_body.hpp +++ b/include/beast/http/basic_dynabuf_body.hpp @@ -8,8 +8,12 @@ #ifndef BEAST_HTTP_BASIC_DYNABUF_BODY_HPP #define BEAST_HTTP_BASIC_DYNABUF_BODY_HPP -#include +#include +#include +#include +#include #include +#include namespace beast { namespace http { @@ -33,14 +37,19 @@ private: value_type& sb_; public: - template + template explicit reader(message& m) noexcept + basic_dynabuf_body, Fields>& m) noexcept : sb_(m.body) { } + void + init(error_code&) noexcept + { + } + void write(void const* data, std::size_t size, error_code&) noexcept @@ -57,33 +66,32 @@ private: DynamicBuffer const& body_; public: - writer(writer const&) = delete; - writer& operator=(writer const&) = delete; - - template + template explicit writer(message< - isRequest, basic_dynabuf_body, Headers> const& m) + isRequest, basic_dynabuf_body, Fields> const& m) noexcept : body_(m.body) { } void - init(error_code& ec) + init(error_code& ec) noexcept { + beast::detail::ignore_unused(ec); } std::uint64_t - content_length() const + content_length() const noexcept { return body_.size(); } - template + template boost::tribool - operator()(resume_context&&, error_code&, Write&& write) + write(resume_context&&, error_code&, + WriteFunction&& wf) noexcept { - write(body_.data()); + wf(body_.data()); return true; } }; diff --git a/include/beast/http/basic_fields.hpp b/include/beast/http/basic_fields.hpp new file mode 100644 index 000000000..3bc957742 --- /dev/null +++ b/include/beast/http/basic_fields.hpp @@ -0,0 +1,306 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_HTTP_BASIC_FIELDS_HPP +#define BEAST_HTTP_BASIC_FIELDS_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace http { + +/** A container for storing HTTP header fields. + + This container is designed to store the field value pairs that make + up the fields and trailers in a HTTP message. Objects of this type + are iterable, with each element holding the field name and field + value. + + Field names are stored as-is, but comparisons are case-insensitive. + When the container is iterated, the fields are presented in the order + of insertion. For fields with the same name, the container behaves + as a `std::multiset`; there will be a separate value for each occurrence + of the field name. + + @note Meets the requirements of @b FieldSequence. +*/ +template +class basic_fields : +#if ! GENERATING_DOCS + private beast::detail::empty_base_optimization< + typename std::allocator_traits:: + template rebind_alloc< + detail::basic_fields_base::element>>, +#endif + public detail::basic_fields_base +{ + using alloc_type = typename + std::allocator_traits:: + template rebind_alloc< + detail::basic_fields_base::element>; + + using alloc_traits = + std::allocator_traits; + + using size_type = + typename std::allocator_traits::size_type; + + void + delete_all(); + + void + move_assign(basic_fields&, std::false_type); + + void + move_assign(basic_fields&, std::true_type); + + void + copy_assign(basic_fields const&, std::false_type); + + void + copy_assign(basic_fields const&, std::true_type); + + template + void + copy_from(FieldSequence const& fs) + { + for(auto const& e : fs) + insert(e.first, e.second); + } + +public: + /// The type of allocator used. + using allocator_type = Allocator; + + /** The value type of the field sequence. + + Meets the requirements of @b Field. + */ +#if GENERATING_DOCS + using value_type = implementation_defined; +#endif + + /// A const iterator to the field sequence +#if GENERATING_DOCS + using iterator = implementation_defined; +#endif + + /// A const iterator to the field sequence +#if GENERATING_DOCS + using const_iterator = implementation_defined; +#endif + + /// Default constructor. + basic_fields() = default; + + /// Destructor + ~basic_fields(); + + /** Construct the fields. + + @param alloc The allocator to use. + */ + explicit + basic_fields(Allocator const& alloc); + + /** Move constructor. + + The moved-from object becomes an empty field sequence. + + @param other The object to move from. + */ + basic_fields(basic_fields&& other); + + /** Move assignment. + + The moved-from object becomes an empty field sequence. + + @param other The object to move from. + */ + basic_fields& operator=(basic_fields&& other); + + /// Copy constructor. + basic_fields(basic_fields const&); + + /// Copy assignment. + basic_fields& operator=(basic_fields const&); + + /// Copy constructor. + template + basic_fields(basic_fields const&); + + /// Copy assignment. + template + basic_fields& operator=(basic_fields const&); + + /// Construct from a field sequence. + template + basic_fields(FwdIt first, FwdIt last); + + /// Returns `true` if the field sequence contains no elements. + bool + empty() const + { + return set_.empty(); + } + + /// Returns the number of elements in the field sequence. + std::size_t + size() const + { + return set_.size(); + } + + /// Returns a const iterator to the beginning of the field sequence. + const_iterator + begin() const + { + return list_.cbegin(); + } + + /// Returns a const iterator to the end of the field sequence. + const_iterator + end() const + { + return list_.cend(); + } + + /// Returns a const iterator to the beginning of the field sequence. + const_iterator + cbegin() const + { + return list_.cbegin(); + } + + /// Returns a const iterator to the end of the field sequence. + const_iterator + cend() const + { + return list_.cend(); + } + + /// Returns `true` if the specified field exists. + bool + exists(boost::string_ref const& name) const + { + return set_.find(name, less{}) != set_.end(); + } + + /// Returns the number of values for the specified field. + std::size_t + count(boost::string_ref const& name) const; + + /** Returns an iterator to the case-insensitive matching field name. + + If more than one field with the specified name exists, the + first field defined by insertion order is returned. + */ + iterator + find(boost::string_ref const& name) const; + + /** Returns the value for a case-insensitive matching header, or `""`. + + If more than one field with the specified name exists, the + first field defined by insertion order is returned. + */ + boost::string_ref + operator[](boost::string_ref const& name) const; + + /// Clear the contents of the basic_fields. + void + clear() noexcept; + + /** Remove a field. + + If more than one field with the specified name exists, all + matching fields will be removed. + + @param name The name of the field(s) to remove. + + @return The number of fields removed. + */ + std::size_t + erase(boost::string_ref const& name); + + /** Insert a field value. + + If a field with the same name already exists, the + existing field is untouched and a new field value pair + is inserted into the container. + + @param name The name of the field. + + @param value A string holding the value of the field. + */ + void + insert(boost::string_ref const& name, boost::string_ref value); + + /** Insert a field value. + + If a field with the same name already exists, the + existing field is untouched and a new field value pair + is inserted into the container. + + @param name The name of the field + + @param value The value of the field. The object will be + converted to a string using `boost::lexical_cast`. + */ + template + typename std::enable_if< + ! std::is_constructible::value>::type + insert(boost::string_ref name, T const& value) + { + insert(name, boost::lexical_cast(value)); + } + + /** Replace a field value. + + First removes any values with matching field names, then + inserts the new field value. + + @param name The name of the field. + + @param value A string holding the value of the field. + */ + void + replace(boost::string_ref const& name, boost::string_ref value); + + /** Replace a field value. + + First removes any values with matching field names, then + inserts the new field value. + + @param name The name of the field + + @param value The value of the field. The object will be + converted to a string using `boost::lexical_cast`. + */ + template + typename std::enable_if< + ! std::is_constructible::value>::type + replace(boost::string_ref const& name, T const& value) + { + replace(name, + boost::lexical_cast(value)); + } +}; + +} // http +} // beast + +#include + +#endif diff --git a/include/beast/http/basic_headers.hpp b/include/beast/http/basic_headers.hpp deleted file mode 100644 index 8972ae343..000000000 --- a/include/beast/http/basic_headers.hpp +++ /dev/null @@ -1,474 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_HTTP_BASIC_HEADERS_HPP -#define BEAST_HTTP_BASIC_HEADERS_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace beast { -namespace http { - -template -class basic_headers; - -namespace detail { - -class basic_headers_base -{ -public: - struct value_type - { - std::string first; - std::string second; - - value_type(boost::string_ref const& name_, - boost::string_ref const& value_) - : first(name_) - , second(value_) - { - } - - boost::string_ref - name() const - { - return first; - } - - boost::string_ref - value() const - { - return second; - } - }; - -protected: - template - friend class beast::http::basic_headers; - - struct element - : boost::intrusive::set_base_hook < - boost::intrusive::link_mode < - boost::intrusive::normal_link>> - , boost::intrusive::list_base_hook < - boost::intrusive::link_mode < - boost::intrusive::normal_link>> - { - value_type data; - - element(boost::string_ref const& name, - boost::string_ref const& value) - : data(name, value) - { - } - }; - - struct less : private beast::detail::ci_less - { - template - bool - operator()(String const& lhs, element const& rhs) const - { - return ci_less::operator()(lhs, rhs.data.first); - } - - template - bool - operator()(element const& lhs, String const& rhs) const - { - return ci_less::operator()(lhs.data.first, rhs); - } - - bool - operator()(element const& lhs, element const& rhs) const - { - return ci_less::operator()( - lhs.data.first, rhs.data.first); - } - }; - - using list_t = typename boost::intrusive::make_list< - element, boost::intrusive::constant_time_size>::type; - - using set_t = typename boost::intrusive::make_multiset< - element, boost::intrusive::constant_time_size, - boost::intrusive::compare>::type; - - // data - set_t set_; - list_t list_; - - basic_headers_base(set_t&& set, list_t&& list) - : set_(std::move(set)) - , list_(std::move(list)) - { - } - -public: - class const_iterator; - - using iterator = const_iterator; - - basic_headers_base() = default; - - /// Returns an iterator to the beginning of the field sequence. - iterator - begin() const; - - /// Returns an iterator to the end of the field sequence. - iterator - end() const; - - /// Returns an iterator to the beginning of the field sequence. - iterator - cbegin() const; - - /// Returns an iterator to the end of the field sequence. - iterator - cend() const; -}; - -//------------------------------------------------------------------------------ - -class basic_headers_base::const_iterator -{ - using iter_type = list_t::const_iterator; - - iter_type it_; - - template - friend class beast::http::basic_headers; - - friend class basic_headers_base; - - const_iterator(iter_type it) - : it_(it) - { - } - -public: - using value_type = - typename basic_headers_base::value_type; - using pointer = value_type const*; - using reference = value_type const&; - using difference_type = std::ptrdiff_t; - using iterator_category = - std::bidirectional_iterator_tag; - - const_iterator() = default; - const_iterator(const_iterator&& other) = default; - const_iterator(const_iterator const& other) = default; - const_iterator& operator=(const_iterator&& other) = default; - const_iterator& operator=(const_iterator const& other) = default; - - bool - operator==(const_iterator const& other) const - { - return it_ == other.it_; - } - - bool - operator!=(const_iterator const& other) const - { - return !(*this == other); - } - - reference - operator*() const - { - return it_->data; - } - - pointer - operator->() const - { - return &**this; - } - - const_iterator& - operator++() - { - ++it_; - return *this; - } - - const_iterator - operator++(int) - { - auto temp = *this; - ++(*this); - return temp; - } - - const_iterator& - operator--() - { - --it_; - return *this; - } - - const_iterator - operator--(int) - { - auto temp = *this; - --(*this); - return temp; - } -}; - -} // detail - -//------------------------------------------------------------------------------ - -/** A container for storing HTTP headers. - - This container is designed to store the field value pairs that make - up the headers and trailers in a HTTP message. Objects of this type - are iterable, which each element holding the field name and field - value. - - Field names are stored as-is, but comparison are case-insensitive. - When the container is iterated, the fields are presented in the order - of insertion. For fields with the same name, the container behaves - as a std::multiset; there will be a separate value for each occurrence - of the field name. - - @note Meets the requirements of @b `FieldSequence`. -*/ -template -class basic_headers -#if ! GENERATING_DOCS - : private beast::detail::empty_base_optimization< - typename std::allocator_traits:: - template rebind_alloc< - detail::basic_headers_base::element>> - , public detail::basic_headers_base -#endif -{ - using alloc_type = typename - std::allocator_traits:: - template rebind_alloc< - detail::basic_headers_base::element>; - - using alloc_traits = - std::allocator_traits; - - using size_type = - typename std::allocator_traits::size_type; - - void - delete_all(); - - void - move_assign(basic_headers&, std::false_type); - - void - move_assign(basic_headers&, std::true_type); - - void - copy_assign(basic_headers const&, std::false_type); - - void - copy_assign(basic_headers const&, std::true_type); - - template - void - copy_from(FieldSequence const& fs) - { - for(auto const& e : fs) - insert(e.first, e.second); - } - -public: - /// The type of allocator used. - using allocator_type = Allocator; - - /// Default constructor. - basic_headers() = default; - - /// Destructor - ~basic_headers(); - - /** Construct the headers. - - @param alloc The allocator to use. - */ - explicit - basic_headers(Allocator const& alloc); - - /** Move constructor. - - The moved-from object becomes an empty field sequence. - - @param other The object to move from. - */ - basic_headers(basic_headers&& other); - - /** Move assignment. - - The moved-from object becomes an empty field sequence. - - @param other The object to move from. - */ - basic_headers& operator=(basic_headers&& other); - - /// Copy constructor. - basic_headers(basic_headers const&); - - /// Copy assignment. - basic_headers& operator=(basic_headers const&); - - /// Copy constructor. - template - basic_headers(basic_headers const&); - - /// Copy assignment. - template - basic_headers& operator=(basic_headers const&); - - /// Construct from a field sequence. - template - basic_headers(FwdIt first, FwdIt last); - - /// Returns `true` if the field sequence contains no elements. - bool - empty() const - { - return set_.empty(); - } - - /// Returns the number of elements in the field sequence. - std::size_t - size() const - { - return set_.size(); - } - - /// Returns `true` if the specified field exists. - bool - exists(boost::string_ref const& name) const - { - return set_.find(name, less{}) != set_.end(); - } - - /// Returns the number of values for the specified field. - std::size_t - count(boost::string_ref const& name) const; - - /** Returns an iterator to the case-insensitive matching field name. - - If more than one field with the specified name exists, the - first field defined by insertion order is returned. - */ - iterator - find(boost::string_ref const& name) const; - - /** Returns the value for a case-insensitive matching header, or `""`. - - If more than one field with the specified name exists, the - first field defined by insertion order is returned. - */ - boost::string_ref - operator[](boost::string_ref const& name) const; - - /// Clear the contents of the basic_headers. - void - clear() noexcept; - - /** Remove a field. - - If more than one field with the specified name exists, all - matching fields will be removed. - - @param name The name of the field(s) to remove. - - @return The number of fields removed. - */ - std::size_t - erase(boost::string_ref const& name); - - /** Insert a field value. - - If a field with the same name already exists, the - existing field is untouched and a new field value pair - is inserted into the container. - - @param name The name of the field. - - @param value A string holding the value of the field. - */ - void - insert(boost::string_ref const& name, boost::string_ref value); - - /** Insert a field value. - - If a field with the same name already exists, the - existing field is untouched and a new field value pair - is inserted into the container. - - @param name The name of the field - - @param value The value of the field. The object will be - converted to a string using `boost::lexical_cast`. - */ - template - typename std::enable_if< - ! std::is_constructible::value>::type - insert(boost::string_ref name, T const& value) - { - insert(name, boost::lexical_cast(value)); - } - - /** Replace a field value. - - First removes any values with matching field names, then - inserts the new field value. - - @param name The name of the field. - - @param value A string holding the value of the field. - */ - void - replace(boost::string_ref const& name, boost::string_ref value); - - /** Replace a field value. - - First removes any values with matching field names, then - inserts the new field value. - - @param name The name of the field - - @param value The value of the field. The object will be - converted to a string using `boost::lexical_cast`. - */ - template - typename std::enable_if< - ! std::is_constructible::value>::type - replace(boost::string_ref const& name, T const& value) - { - replace(name, - boost::lexical_cast(value)); - } -}; - -} // http -} // beast - -#include - -#endif diff --git a/include/beast/http/basic_parser_v1.hpp b/include/beast/http/basic_parser_v1.hpp index 555d3f6ea..70e9e06cb 100644 --- a/include/beast/http/basic_parser_v1.hpp +++ b/include/beast/http/basic_parser_v1.hpp @@ -13,8 +13,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -22,8 +22,11 @@ namespace beast { namespace http { -namespace parse_flag { -enum values +/** Parse flags + + The set of parser bit flags are returned by @ref basic_parser_v1::flags. +*/ +enum parse_flag { chunked = 1, connection_keep_alive = 2, @@ -34,28 +37,6 @@ enum values skipbody = 64, contentlength = 128 }; -} // parse_flag - -/** Headers maximum size option. - - Sets the maximum number of cumulative bytes allowed - including all header octets. A value of zero indicates - no limit on the number of header octets - - The default headers maximum size is 16KB (16,384 bytes). - - @note Objects of this type are passed to @ref set_option. -*/ -struct headers_max_size -{ - std::size_t value; - - explicit - headers_max_size(std::size_t v) - : value(v) - { - } -}; /** Body maximum size option. @@ -67,7 +48,7 @@ struct headers_max_size The default body maximum size for requests is 4MB (four megabytes or 4,194,304 bytes) and unlimited for responses. - @note Objects of this type are passed to @ref set_option. + @note Objects of this type are used with @ref basic_parser_v1::set_option. */ struct body_max_size { @@ -80,9 +61,73 @@ struct body_max_size } }; +/** Header maximum size option. + + Sets the maximum number of cumulative bytes allowed + including all header octets. A value of zero indicates + no limit on the number of header octets. + + The default header maximum size is 16KB (16,384 bytes). + + @note Objects of this type are used with @ref basic_parser_v1::set_option. +*/ +struct header_max_size +{ + std::size_t value; + + explicit + header_max_size(std::size_t v) + : value(v) + { + } +}; + +/** A value indicating how the parser should treat the body. + + This value is returned from the `on_header` callback in + the derived class. It controls what the parser does next + in terms of the message body. +*/ +enum class body_what +{ + /** The parser should expect a body, keep reading. + */ + normal, + + /** Skip parsing of the body. + + When returned by `on_header` this causes parsing to + complete and control to return to the caller. This + could be used when sending a response to a HEAD + request, for example. + */ + skip, + + /** The message represents an UPGRADE request. + + When returned by `on_body_prepare` this causes parsing + to complete and control to return to the caller. + */ + upgrade, + + /** Suspend parsing before reading the body. + + When returned by `on_body_prepare` this causes parsing + to pause. Control is returned to the caller, and the + parser state is preserved such that a subsequent call + to the parser will begin reading the message body. + + This could be used by callers to inspect the HTTP + header before committing to read the body. For example, + to choose the body type based on the fields. Or to + respond to an Expect: 100-continue request. + */ + pause +}; + /// The value returned when no content length is known or applicable. static std::uint64_t constexpr no_content_length = - std::numeric_limits::max(); + (std::numeric_limits::max)(); /** A parser for decoding HTTP/1 wire format messages. @@ -97,86 +142,95 @@ static std::uint64_t constexpr no_content_length = more calls to derived class members functions (referred to as "callbacks" from here on) matching a specific signature. - Callbacks are detected through SFINAE. The derived class may - implement as few or as many of the members as needed. - These are the signatures of the callbacks:
    + Every callback must be provided by the derived class, or else + a compilation error will be generated. This exemplar shows + the signature and description of the callbacks required in + the derived class. - @li `void on_start(error_code&)` + @code + template + struct exemplar : basic_parser_v1 + { + // Called when the first valid octet of a new message is received + // + void on_start(error_code&); - Called when the first valid octet of a new message is received + // Called for each piece of the Request-Method + // + void on_method(boost::string_ref const&, error_code&); - @li `void on_method(boost::string_ref const&, error_code&)` + // Called for each piece of the Request-URI + // + void on_uri(boost::string_ref const&, error_code&); - Called for each piece of the Request-Method + // Called for each piece of the reason-phrase + // + void on_reason(boost::string_ref const&, error_code&); - @li `void on_uri(boost::string_ref const&, error_code&)` + // Called after the entire Request-Line has been parsed successfully. + // + void on_request(error_code&); - Called for each piece of the Request-URI + // Called after the entire Response-Line has been parsed successfully. + // + void on_response(error_code&); - @li `void on_reason(boost::string_ref const&, error_code&)` + // Called for each piece of the current header field. + // + void on_field(boost::string_ref const&, error_code&); - Called for each piece of the reason-phrase + // Called for each piece of the current header value. + // + void on_value(boost::string_ref const&, error_code&) - @li `void on_request(error_code&)` + // Called when the entire header has been parsed successfully. + // + void + on_header(std::uint64_t content_length, error_code&); - Called after the entire Request-Line has been parsed successfully. + // Called after on_header, before the body is parsed + // + body_what + on_body_what(std::uint64_t content_length, error_code&); - @li `void on_response(error_code&)` + // Called for each piece of the body. + // + // If the header indicates chunk encoding, the chunk + // encoding is removed from the buffer before being + // passed to the callback. + // + void on_body(boost::string_ref const&, error_code&); - Called after the entire Response-Line has been parsed successfully. + // Called when the entire message has been parsed successfully. + // At this point, @ref complete returns `true`, and the parser + // is ready to parse another message if `keep_alive` would + // return `true`. + // + void on_complete(error_code&) {} + }; + @endcode - @li `void on_field(boost::string_ref const&, error_code&)` - - Called for each piece of the current header field. - - @li `void on_value(boost::string_ref const&, error_code&)` - - Called for each piece of the current header value. - - @li `int on_headers(std::uint64_t content_length, error_code&)` - - Called when all the headers have been parsed successfully. - - @li `void on_body(boost::string_ref const&, error_code&)` - - Called for each piece of the body. If the headers indicated - chunked encoding, the chunk encoding is removed from the - buffer before being passed to the callback. - - @li `void on_complete(error_code&)` - - Called when the entire message has been parsed successfully. - At this point, @ref basic_parser_v1::complete returns `true`, and - the parser is ready to parse another message if keep_alive - would return `true`. - - The return value of `on_headers` is special, it controls whether - or not the parser should expect a body. These are the return values: - - @li *0* The parser should expect a body - - @li *1* The parser should skip the body. For example, this is - used when sending a response to a HEAD request. - - @li *2* The parser should skip ths body, this is an - upgrade to a different protocol. - - The parser uses traits to determine if the callback is possible. - If the Derived type omits one or more callbacks, they are simply - skipped with no compilation error. The default behavior of `on_body` - when the derived class does not provide the member, is to specify that - the body should not be skipped. + The return value of `on_body_what` is special, it controls + whether or not the parser should expect a body. See @ref body_what + for choices of the return value. If a callback sets an error, parsing stops at the current octet - and the error is returned to the caller. + and the error is returned to the caller. Callbacks must not throw + exceptions. @tparam isRequest A `bool` indicating whether the parser will be presented with request or response message. + + @tparam Derived The derived class type. This is part of the + Curiously Recurring Template Pattern interface. */ template class basic_parser_v1 : public detail::parser_base { private: + template + friend class basic_parser_v1; + using self = basic_parser_v1; typedef void(self::*pmf_t)(error_code&, boost::string_ref const&); @@ -235,15 +289,19 @@ private: bool upgrade_ : 1; // true if parser exited for upgrade public: - /// Copy constructor. - basic_parser_v1(basic_parser_v1 const&) = default; - - /// Copy assignment. - basic_parser_v1& operator=(basic_parser_v1 const&) = default; - /// Default constructor basic_parser_v1(); + /// Copy constructor. + template + basic_parser_v1(basic_parser_v1< + isRequest, OtherDerived> const& other); + + /// Copy assignment. + template + basic_parser_v1& operator=(basic_parser_v1< + isRequest, OtherDerived> const& other); + /** Set options on the parser. @param args One or more parser options to set. @@ -263,9 +321,9 @@ public: std::forward(an)...); } - /// Set the headers maximum size option + /// Set the header maximum size option void - set_option(headers_max_size const& o) + set_option(header_max_size const& o) { h_max_ = o.value; h_left_ = h_max_; @@ -373,7 +431,10 @@ public: bool complete() const { - return s_ == s_restart || s_ == s_closed_complete; + return + s_ == s_restart || + s_ == s_closed_complete || + s_ == s_body_pause; } /** Write a sequence of buffers to the parser. @@ -418,6 +479,15 @@ public: void write_eof(error_code& ec); +protected: + /** Reset the parsing state. + + The state of the parser is reset to expect the beginning of + a new request or response. The old state is discarded. + */ + void + reset(); + private: Derived& impl() @@ -437,18 +507,10 @@ private: s_ = s_res_start; } - void - reset() - { - h_left_ = h_max_; - b_left_ = b_max_; - reset(std::integral_constant{}); - } - void init(std::true_type) { - // 16KB max headers, 4MB max body + // Request: 16KB max header, 4MB max body h_max_ = 16 * 1024; b_max_ = 4 * 1024 * 1024; } @@ -456,7 +518,7 @@ private: void init(std::false_type) { - // 16KB max headers, unlimited body + // Response: 16KB max header, unlimited body h_max_ = 16 * 1024; b_max_ = 0; } @@ -474,13 +536,102 @@ private: bool needs_eof(std::false_type) const; + template> + struct check_on_start : std::false_type {}; + + template + struct check_on_start().on_start( + std::declval()) + )>> : std::true_type { }; + + template> + struct check_on_method : std::false_type {}; + + template + struct check_on_method().on_method( + std::declval(), + std::declval()) + )>> : std::true_type {}; + + template> + struct check_on_uri : std::false_type {}; + + template + struct check_on_uri().on_uri( + std::declval(), + std::declval()) + )>> : std::true_type {}; + + template> + struct check_on_reason : std::false_type {}; + + template + struct check_on_reason().on_reason( + std::declval(), + std::declval()) + )>> : std::true_type {}; + + template> + struct check_on_request : std::false_type {}; + + template + struct check_on_request().on_request( + std::declval()) + )>> : std::true_type {}; + + template> + struct check_on_response : std::false_type {}; + + template + struct check_on_response().on_response( + std::declval()) + )>> : std::true_type {}; + + template> + struct check_on_field : std::false_type {}; + + template + struct check_on_field().on_field( + std::declval(), + std::declval()) + )>> : std::true_type {}; + + template> + struct check_on_value : std::false_type {}; + + template + struct check_on_value().on_value( + std::declval(), + std::declval()) + )>> : std::true_type {}; + + template> + struct check_on_headers : std::false_type {}; + + template + struct check_on_headers().on_header( + std::declval(), + std::declval()) + )>> : std::true_type {}; + + // VFALCO Can we use std::is_detected? Is C++11 capable? template - class has_on_start_t + class check_on_body_what_t { - template().on_start( - std::declval()), - std::true_type{})> + template().on_body_what( + std::declval(), + std::declval())), + body_what>> static R check(int); template static std::false_type check(...); @@ -489,211 +640,46 @@ private: static bool const value = type::value; }; template - using has_on_start = - std::integral_constant::value>; + using check_on_body_what = + std::integral_constant::value>; - template - class has_on_method_t - { - template().on_method( - std::declval(), - std::declval()), - std::true_type{})> - static R check(int); - template - static std::false_type check(...); - using type = decltype(check(0)); - public: - static bool const value = type::value; - }; - template - using has_on_method = - std::integral_constant::value>; + template> + struct check_on_body : std::false_type {}; - template - class has_on_uri_t - { - template().on_uri( - std::declval(), - std::declval()), - std::true_type{})> - static R check(int); - template - static std::false_type check(...); - using type = decltype(check(0)); - public: - static bool const value = type::value; - }; - template - using has_on_uri = - std::integral_constant::value>; + template + struct check_on_body().on_body( + std::declval(), + std::declval()) + )>> : std::true_type {}; - template - class has_on_reason_t - { - template().on_reason( - std::declval(), - std::declval()), - std::true_type{})> - static R check(int); - template - static std::false_type check(...); - using type = decltype(check(0)); - public: - static bool const value = type::value; - }; - template - using has_on_reason = - std::integral_constant::value>; + template> + struct check_on_complete : std::false_type {}; - template - class has_on_request_t - { - template().on_request( - std::declval()), - std::true_type{})> - static R check(int); - template - static std::false_type check(...); - using type = decltype(check(0)); - public: - static bool const value = type::value; - }; - template - using has_on_request = - std::integral_constant::value>; - - template - class has_on_response_t - { - template().on_response( - std::declval()), - std::true_type{})> - static R check(int); - template - static std::false_type check(...); - using type = decltype(check(0)); - public: - static bool const value = type::value; - }; - template - using has_on_response = - std::integral_constant::value>; - - template - class has_on_field_t - { - template().on_uri( - std::declval(), - std::declval()), - std::true_type{})> - static R check(int); - template - static std::false_type check(...); - using type = decltype(check(0)); - public: - static bool const value = type::value; - }; - template - using has_on_field = - std::integral_constant::value>; - - template - class has_on_value_t - { - template().on_uri( - std::declval(), - std::declval()), - std::true_type{})> - static R check(int); - template - static std::false_type check(...); - using type = decltype(check(0)); - public: - static bool const value = type::value; - }; - template - using has_on_value = - std::integral_constant::value>; - - template - class has_on_headers_t - { - template().on_headers( - std::declval(), std::declval()))>> - static R check(int); - template - static std::false_type check(...); - using type = decltype(check(0)); - public: - static bool const value = type::value; - }; - template - using has_on_headers = - std::integral_constant::value>; - - template - class has_on_body_t - { - template().on_body( - std::declval(), - std::declval()), - std::true_type{})> - static R check(int); - template - static std::false_type check(...); - using type = decltype(check(0)); - public: - static bool const value = type::value; - }; - template - using has_on_body = - std::integral_constant::value>; - - template - class has_on_complete_t - { - template().on_complete( - std::declval()), - std::true_type{})> - static R check(int); - template - static std::false_type check(...); - using type = decltype(check(0)); - public: - static bool const value = type::value; - }; - template - using has_on_complete = - std::integral_constant::value>; - - void call_on_start(error_code& ec, std::true_type) - { - impl().on_start(ec); - } - - void call_on_start(error_code& ec, std::false_type) - { - } + template + struct check_on_complete().on_complete( + std::declval()) + )>> : std::true_type {}; void call_on_start(error_code& ec) { - call_on_start(ec, has_on_start{}); + static_assert(check_on_start::value, + "on_start requirements not met"); + impl().on_start(ec); } void call_on_method(error_code& ec, boost::string_ref const& s, std::true_type) { + static_assert(check_on_method::value, + "on_method requirements not met"); + if(h_max_ && s.size() > h_left_) + { + ec = parse_error::header_too_big; + return; + } + h_left_ -= s.size(); impl().on_method(s, ec); } @@ -705,21 +691,21 @@ private: void call_on_method(error_code& ec, boost::string_ref const& s) { - if(! h_max_ || s.size() <= h_left_) - { - h_left_ -= s.size(); - call_on_method(ec, s, std::integral_constant::value>{}); - } - else - { - ec = parse_error::headers_too_big; - } + call_on_method(ec, s, + std::integral_constant{}); } void call_on_uri(error_code& ec, boost::string_ref const& s, std::true_type) { + static_assert(check_on_uri::value, + "on_uri requirements not met"); + if(h_max_ && s.size() > h_left_) + { + ec = parse_error::header_too_big; + return; + } + h_left_ -= s.size(); impl().on_uri(s, ec); } @@ -728,23 +714,24 @@ private: { } - void call_on_uri(error_code& ec, boost::string_ref const& s) + void call_on_uri(error_code& ec, + boost::string_ref const& s) { - if(! h_max_ || s.size() <= h_left_) - { - h_left_ -= s.size(); - call_on_uri(ec, s, std::integral_constant::value>{}); - } - else - { - ec = parse_error::headers_too_big; - } + call_on_uri(ec, s, + std::integral_constant{}); } void call_on_reason(error_code& ec, boost::string_ref const& s, std::true_type) { + static_assert(check_on_reason::value, + "on_reason requirements not met"); + if(h_max_ && s.size() > h_left_) + { + ec = parse_error::header_too_big; + return; + } + h_left_ -= s.size(); impl().on_reason(s, ec); } @@ -755,20 +742,14 @@ private: void call_on_reason(error_code& ec, boost::string_ref const& s) { - if(! h_max_ || s.size() <= h_left_) - { - h_left_ -= s.size(); - call_on_reason(ec, s, std::integral_constant::value>{}); - } - else - { - ec = parse_error::headers_too_big; - } + call_on_reason(ec, s, + std::integral_constant{}); } void call_on_request(error_code& ec, std::true_type) { + static_assert(check_on_request::value, + "on_request requirements not met"); impl().on_request(ec); } @@ -778,12 +759,14 @@ private: void call_on_request(error_code& ec) { - call_on_request(ec, std::integral_constant::value>{}); + call_on_request(ec, + std::integral_constant{}); } void call_on_response(error_code& ec, std::true_type) { + static_assert(check_on_response::value, + "on_response requirements not met"); impl().on_response(ec); } @@ -793,111 +776,73 @@ private: void call_on_response(error_code& ec) { - call_on_response(ec, std::integral_constant::value>{}); + call_on_response(ec, + std::integral_constant{}); } void call_on_field(error_code& ec, - boost::string_ref const& s, std::true_type) + boost::string_ref const& s) { + static_assert(check_on_field::value, + "on_field requirements not met"); + if(h_max_ && s.size() > h_left_) + { + ec = parse_error::header_too_big; + return; + } + h_left_ -= s.size(); impl().on_field(s, ec); } - void call_on_field(error_code&, - boost::string_ref const&, std::false_type) - { - } - - void call_on_field(error_code& ec, boost::string_ref const& s) - { - if(! h_max_ || s.size() <= h_left_) - { - h_left_ -= s.size(); - call_on_field(ec, s, has_on_field{}); - } - else - { - ec = parse_error::headers_too_big; - } - } - void call_on_value(error_code& ec, - boost::string_ref const& s, std::true_type) + boost::string_ref const& s) { + static_assert(check_on_value::value, + "on_value requirements not met"); + if(h_max_ && s.size() > h_left_) + { + ec = parse_error::header_too_big; + return; + } + h_left_ -= s.size(); impl().on_value(s, ec); } - void call_on_value(error_code&, - boost::string_ref const&, std::false_type) + void + call_on_headers(error_code& ec) { + static_assert(check_on_headers::value, + "on_header requirements not met"); + impl().on_header(content_length_, ec); } - void call_on_value(error_code& ec, boost::string_ref const& s) + body_what + call_on_body_what(error_code& ec) { - if(! h_max_ || s.size() <= h_left_) - { - h_left_ -= s.size(); - call_on_value(ec, s, has_on_value{}); - } - else - { - ec = parse_error::headers_too_big; - } - } - - int call_on_headers(error_code& ec, - std::uint64_t content_length, std::true_type) - { - return impl().on_headers(content_length, ec); - } - - int call_on_headers(error_code& ec, std::uint64_t, std::false_type) - { - return 0; - } - - int call_on_headers(error_code& ec) - { - return call_on_headers(ec, content_length_, - has_on_headers{}); + static_assert(check_on_body_what::value, + "on_body_what requirements not met"); + return impl().on_body_what(content_length_, ec); } void call_on_body(error_code& ec, - boost::string_ref const& s, std::true_type) + boost::string_ref const& s) { - impl().on_body(s, ec); - } - - void call_on_body(error_code&, - boost::string_ref const&, std::false_type) - { - } - - void call_on_body(error_code& ec, boost::string_ref const& s) - { - if(! b_max_ || s.size() <= b_left_) - { - b_left_ -= s.size(); - call_on_body(ec, s, has_on_body{}); - } - else + static_assert(check_on_body::value, + "on_body requirements not met"); + if(b_max_ && s.size() > b_left_) { ec = parse_error::body_too_big; + return; } - } - - void call_on_complete(error_code& ec, std::true_type) - { - impl().on_complete(ec); - } - - void call_on_complete(error_code&, std::false_type) - { + b_left_ -= s.size(); + impl().on_body(s, ec); } void call_on_complete(error_code& ec) { - call_on_complete(ec, has_on_complete{}); + static_assert(check_on_complete::value, + "on_complete requirements not met"); + impl().on_complete(ec); } }; diff --git a/include/beast/http/body_type.hpp b/include/beast/http/body_type.hpp deleted file mode 100644 index 5b3f96014..000000000 --- a/include/beast/http/body_type.hpp +++ /dev/null @@ -1,19 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_HTTP_BODY_TYPE_HPP -#define BEAST_HTTP_BODY_TYPE_HPP - -// Convenience header to include everything -// needed when declarating a user defined Body type. - -#include -#include -#include -#include - -#endif diff --git a/include/beast/http/chunk_encode.hpp b/include/beast/http/chunk_encode.hpp new file mode 100644 index 000000000..cb2881b48 --- /dev/null +++ b/include/beast/http/chunk_encode.hpp @@ -0,0 +1,74 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_HTTP_CHUNK_ENCODE_HPP +#define BEAST_HTTP_CHUNK_ENCODE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace http { + +/** Returns a chunk-encoded ConstBufferSequence. + + This returns a buffer sequence representing the + first chunk of a chunked transfer coded body. + + @param fin `true` if this is the last chunk. + + @param buffers The input buffer sequence. + + @return A chunk-encoded ConstBufferSequence representing the input. + + @see
    rfc7230 section 4.1.3 +*/ +template +#if GENERATING_DOCS +implementation_defined +#else +beast::detail::buffer_cat_helper< + detail::chunk_encode_delim, + ConstBufferSequence, + boost::asio::const_buffers_1> +#endif +chunk_encode(bool fin, ConstBufferSequence const& buffers) +{ + using boost::asio::buffer_size; + return buffer_cat( + detail::chunk_encode_delim{buffer_size(buffers)}, + buffers, + fin ? boost::asio::const_buffers_1{"\r\n0\r\n\r\n", 7} + : boost::asio::const_buffers_1{"\r\n", 2}); +} + +/** Returns a chunked encoding final chunk. + + @see rfc7230 section 4.1.3 +*/ +inline +#if GENERATING_DOCS +implementation_defined +#else +boost::asio::const_buffers_1 +#endif +chunk_encode_final() +{ + return boost::asio::const_buffers_1{"0\r\n\r\n", 5}; +} + +} // http +} // beast + +#endif diff --git a/include/beast/http/concepts.hpp b/include/beast/http/concepts.hpp index d8641050a..f77777de3 100644 --- a/include/beast/http/concepts.hpp +++ b/include/beast/http/concepts.hpp @@ -9,7 +9,10 @@ #define BEAST_HTTP_TYPE_CHECK_HPP #include +#include +#include #include +#include #include #include @@ -18,65 +21,107 @@ namespace http { namespace detail { -template -class has_value_type +struct write_function { - template - static std::true_type check(int); + template + void + operator()(ConstBufferSequence const&); +}; + +template> +struct has_value_type : std::false_type {}; + +template +struct has_value_type > : std::true_type {}; + +template> +struct has_content_length : std::false_type {}; + +template +struct has_content_length().content_length() + )> > : std::true_type +{ + static_assert(std::is_convertible< + decltype(std::declval().content_length()), + std::uint64_t>::value, + "Writer::content_length requirements not met"); +}; + +#if 0 +template> +struct is_Writer : std::false_type {}; + +template +struct is_Writer().init( + std::declval()) + // VFALCO This is unfortunate, we have to provide the template + // argument type because this is not a deduced context? + // + ,std::declval().template write( + std::declval(), + std::declval(), + std::declval()) + )> > : std::integral_constant::value && + std::is_convertible().template write( + std::declval(), + std::declval(), + std::declval())), + boost::tribool>::value + > +{ + static_assert(std::is_same< + typename M::body_type::writer, T>::value, + "Mismatched writer and message"); +}; + +#else + +template +class is_Writer +{ + template().init(std::declval()), + std::true_type{})> + static R check1(int); template - static std::false_type check(...); - using type = decltype(check(0)); -public: - static bool constexpr value = type::value; -}; + static std::false_type check1(...); + using type1 = decltype(check1(0)); -template::value> -struct extract_value_type -{ - using type = void; -}; - -template -struct extract_value_type -{ - using type = typename T::value_type; -}; - -template -class has_reader -{ + // VFALCO This is unfortunate, we have to provide the template + // argument type because this is not a deduced context? + // template - static std::true_type check(int); + std::is_convertible().template write( + std::declval(), + std::declval(), + std::declval())) + , boost::tribool>> + static R check2(int); template - static std::false_type check(...); -public: - using type = decltype(check(0)); -}; + static std::false_type check2(...); + using type2 = decltype(check2(0)); -template -class has_writer -{ - template - static std::true_type check(int); - template - static std::false_type check(...); public: - using type = decltype(check(0)); -}; + static_assert(std::is_same< + typename M::body_type::writer, T>::value, + "Mismatched writer and message"); -template -struct is_Body -{ using type = std::integral_constant::value && - std::is_default_constructible< - typename extract_value_type::type>::value + std::is_nothrow_constructible::value + && type1::value + && type2::value >; }; +#endif + template class is_Parser { @@ -92,7 +137,7 @@ class is_Parser template().write( - std::declval(), + std::declval(), std::declval())), std::size_t>> static R check2(int); @@ -118,31 +163,97 @@ public: } // detail -/// Determine if `T` meets the requirements of `Body`. +/// Determine if `T` meets the requirements of @b Body. template #if GENERATING_DOCS struct is_Body : std::integral_constant{}; #else -using is_Body = typename detail::is_Body::type; +using is_Body = detail::has_value_type; #endif -/// Determine if `T` meets the requirements of `ReadableBody`. -template +/** Determine if a @b Body has a nested type `reader`. + + @tparam T The type to check, which must meet the + requirements of @b Body. +*/ #if GENERATING_DOCS -struct is_ReadableBody : std::integral_constant{}; -#else -using is_ReadableBody = typename detail::has_reader::type; -#endif - -/// Determine if `T` meets the requirements of `WritableBody`. template -#if GENERATING_DOCS -struct is_WritableBody : std::integral_constant{}; +struct has_reader : std::integral_constant{}; #else -using is_WritableBody = typename detail::has_writer::type; +template> +struct has_reader : std::false_type {}; + +template +struct has_reader > : std::true_type {}; #endif -/// Determine if `T` meets the requirements of `Parser`. +/** Determine if a @b Body has a nested type `writer`. + + @tparam T The type to check, which must meet the + requirements of @b Body. +*/ +#if GENERATING_DOCS +template +struct has_writer : std::integral_constant{}; +#else +template> +struct has_writer : std::false_type {}; + +template +struct has_writer > : std::true_type {}; +#endif + +/** Determine if `T` meets the requirements of @b Reader for `M`. + + @tparam T The type to test. + + @tparam M The message type to test with, which must be of + type `message`. +*/ +#if GENERATING_DOCS +template +struct is_Reader : std::integral_constant {}; +#else +template> +struct is_Reader : std::false_type {}; + +template +struct is_Reader().init( + std::declval()), + std::declval().write( + std::declval(), + std::declval(), + std::declval()) + )> > : std::integral_constant::value + > +{ + static_assert(std::is_same< + typename M::body_type::reader, T>::value, + "Mismatched reader and message"); +}; +#endif + +/** Determine if `T` meets the requirements of @b Writer for `M`. + + @tparam T The type to test. + + @tparam M The message type to test with, which must be of + type `message`. +*/ +template +#if GENERATING_DOCS +struct is_Writer : std::integral_constant {}; +#else +using is_Writer = typename detail::is_Writer::type; +#endif + +/// Determine if `T` meets the requirements of @b Parser. template #if GENERATING_DOCS struct is_Parser : std::integral_constant{}; diff --git a/include/beast/http/detail/basic_fields.hpp b/include/beast/http/detail/basic_fields.hpp new file mode 100644 index 000000000..a60b30f2b --- /dev/null +++ b/include/beast/http/detail/basic_fields.hpp @@ -0,0 +1,214 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_HTTP_DETAIL_BASIC_FIELDS_HPP +#define BEAST_HTTP_DETAIL_BASIC_FIELDS_HPP + +#include +#include +#include +#include + +namespace beast { +namespace http { + +template +class basic_fields; + +namespace detail { + +class basic_fields_base +{ +public: + struct value_type + { + std::string first; + std::string second; + + value_type(boost::string_ref const& name_, + boost::string_ref const& value_) + : first(name_) + , second(value_) + { + } + + boost::string_ref + name() const + { + return first; + } + + boost::string_ref + value() const + { + return second; + } + }; + +protected: + template + friend class beast::http::basic_fields; + + struct element + : boost::intrusive::set_base_hook < + boost::intrusive::link_mode < + boost::intrusive::normal_link>> + , boost::intrusive::list_base_hook < + boost::intrusive::link_mode < + boost::intrusive::normal_link>> + { + value_type data; + + element(boost::string_ref const& name, + boost::string_ref const& value) + : data(name, value) + { + } + }; + + struct less : private beast::detail::ci_less + { + template + bool + operator()(String const& lhs, element const& rhs) const + { + return ci_less::operator()(lhs, rhs.data.first); + } + + template + bool + operator()(element const& lhs, String const& rhs) const + { + return ci_less::operator()(lhs.data.first, rhs); + } + + bool + operator()(element const& lhs, element const& rhs) const + { + return ci_less::operator()( + lhs.data.first, rhs.data.first); + } + }; + + using list_t = typename boost::intrusive::make_list< + element, boost::intrusive::constant_time_size>::type; + + using set_t = typename boost::intrusive::make_multiset< + element, boost::intrusive::constant_time_size, + boost::intrusive::compare>::type; + + // data + set_t set_; + list_t list_; + + basic_fields_base(set_t&& set, list_t&& list) + : set_(std::move(set)) + , list_(std::move(list)) + { + } + +public: + class const_iterator; + + using iterator = const_iterator; + + basic_fields_base() = default; +}; + +//------------------------------------------------------------------------------ + +class basic_fields_base::const_iterator +{ + using iter_type = list_t::const_iterator; + + iter_type it_; + + template + friend class beast::http::basic_fields; + + friend class basic_fields_base; + + const_iterator(iter_type it) + : it_(it) + { + } + +public: + using value_type = + typename basic_fields_base::value_type; + using pointer = value_type const*; + using reference = value_type const&; + using difference_type = std::ptrdiff_t; + using iterator_category = + std::bidirectional_iterator_tag; + + const_iterator() = default; + const_iterator(const_iterator&& other) = default; + const_iterator(const_iterator const& other) = default; + const_iterator& operator=(const_iterator&& other) = default; + const_iterator& operator=(const_iterator const& other) = default; + + bool + operator==(const_iterator const& other) const + { + return it_ == other.it_; + } + + bool + operator!=(const_iterator const& other) const + { + return !(*this == other); + } + + reference + operator*() const + { + return it_->data; + } + + pointer + operator->() const + { + return &**this; + } + + const_iterator& + operator++() + { + ++it_; + return *this; + } + + const_iterator + operator++(int) + { + auto temp = *this; + ++(*this); + return temp; + } + + const_iterator& + operator--() + { + --it_; + return *this; + } + + const_iterator + operator--(int) + { + auto temp = *this; + --(*this); + return temp; + } +}; + +} // detail +} // http +} // beast + +#endif diff --git a/include/beast/http/detail/basic_parser_v1.hpp b/include/beast/http/detail/basic_parser_v1.hpp index 196089bca..30f9e7bec 100644 --- a/include/beast/http/detail/basic_parser_v1.hpp +++ b/include/beast/http/detail/basic_parser_v1.hpp @@ -8,9 +8,6 @@ #ifndef BEAST_HTTP_DETAIL_BASIC_PARSER_V1_HPP #define BEAST_HTTP_DETAIL_BASIC_PARSER_V1_HPP -#include -#include -#include #include namespace beast { @@ -130,6 +127,7 @@ protected: s_chunk_data_cr, s_chunk_data_lf, + s_body_pause, s_body_identity0, s_body_identity, s_body_identity_eof0, diff --git a/include/beast/http/detail/chunk_encode.hpp b/include/beast/http/detail/chunk_encode.hpp index 62accf163..e2ebb8123 100644 --- a/include/beast/http/detail/chunk_encode.hpp +++ b/include/beast/http/detail/chunk_encode.hpp @@ -8,27 +8,30 @@ #ifndef BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP #define BEAST_HTTP_DETAIL_CHUNK_ENCODE_HPP -#include #include -#include #include #include -#include #include -#include -#include namespace beast { namespace http { namespace detail { -class chunk_encode_text +class chunk_encode_delim { boost::asio::const_buffer cb_; // Storage for the longest hex string we might need, plus delimiters. std::array buf_; + template + void + copy(chunk_encode_delim const& other); + + template + void + setup(std::size_t n); + template static OutIter @@ -52,24 +55,15 @@ public: using const_iterator = value_type const*; - chunk_encode_text(chunk_encode_text const& other) + chunk_encode_delim(chunk_encode_delim const& other) { - auto const n = - boost::asio::buffer_size(other.cb_); - buf_ = other.buf_; - cb_ = boost::asio::const_buffer( - &buf_[buf_.size() - n], n); + copy(other); } explicit - chunk_encode_text(std::size_t n) + chunk_encode_delim(std::size_t n) { - buf_[buf_.size() - 2] = '\r'; - buf_[buf_.size() - 1] = '\n'; - auto it = to_hex(buf_.end() - 2, n); - cb_ = boost::asio::const_buffer{&*it, - static_cast( - std::distance(it, buf_.end()))}; + setup(n); } const_iterator @@ -85,44 +79,29 @@ public: } }; -/** Returns a chunk-encoded ConstBufferSequence. - - This returns a buffer sequence representing the - first chunk of a chunked transfer coded body. - - @param buffers The input buffer sequence. - - @return A chunk-encoded ConstBufferSequence representing the input. - - @see rfc7230 section 4.1.3 -*/ -template -#if GENERATING_DOCS -implementation_defined -#else -beast::detail::buffer_cat_helper -#endif -chunk_encode(ConstBufferSequence const& buffers) +template +void +chunk_encode_delim:: +copy(chunk_encode_delim const& other) { - using boost::asio::buffer_size; - return buffer_cat( - chunk_encode_text{buffer_size(buffers)}, - buffers, - boost::asio::const_buffers_1{"\r\n", 2}); + auto const n = + boost::asio::buffer_size(other.cb_); + buf_ = other.buf_; + cb_ = boost::asio::const_buffer( + &buf_[buf_.size() - n], n); } -/// Returns a chunked encoding final chunk. -inline -#if GENERATING_DOCS -implementation_defined -#else -boost::asio::const_buffers_1 -#endif -chunk_encode_final() +template +void +chunk_encode_delim:: +setup(std::size_t n) { - return boost::asio::const_buffers_1( - "0\r\n\r\n", 5); + buf_[buf_.size() - 2] = '\r'; + buf_[buf_.size() - 1] = '\n'; + auto it = to_hex(buf_.end() - 2, n); + cb_ = boost::asio::const_buffer{&*it, + static_cast( + std::distance(it, buf_.end()))}; } } // detail diff --git a/include/beast/http/detail/has_content_length.hpp b/include/beast/http/detail/has_content_length.hpp deleted file mode 100644 index 09584a5ea..000000000 --- a/include/beast/http/detail/has_content_length.hpp +++ /dev/null @@ -1,43 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_HTTP_DETAIL_HAS_CONTENT_LENGTH_HPP -#define BEAST_HTTP_DETAIL_HAS_CONTENT_LENGTH_HPP - -#include -#include - -namespace beast { -namespace http { -namespace detail { - -template -class has_content_length_value -{ - template().content_length()), - std::uint64_t>> - static R check(int); - template - static std::false_type check(...); - using type = decltype(check(0)); -public: - // `true` if `T` meets the requirements. - static bool const value = type::value; -}; - -// Determines if the writer can provide the content length -template -using has_content_length = - std::integral_constant::value>; - -} // detail -} // http -} // beast - -#endif diff --git a/include/beast/http/detail/rfc7230.hpp b/include/beast/http/detail/rfc7230.hpp index dc9285a5f..191eaeedd 100644 --- a/include/beast/http/detail/rfc7230.hpp +++ b/include/beast/http/detail/rfc7230.hpp @@ -233,6 +233,14 @@ skip_ows(FwdIt& it, FwdIt const& end) } } +template +void +skip_token(FwdIt& it, FwdIt const& last) +{ + while(it != last && is_tchar(*it)) + ++it; +} + inline boost::string_ref trim(boost::string_ref const& s) @@ -258,14 +266,14 @@ struct param_iter using iter_type = boost::string_ref::const_iterator; iter_type it; - iter_type begin; - iter_type end; + iter_type first; + iter_type last; std::pair v; bool empty() const { - return begin == it; + return first == it; } template @@ -279,59 +287,48 @@ param_iter:: increment() { /* - ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] ) - ext = token param-list - param-list = *( OWS ";" OWS param ) - param = token OWS "=" OWS ( token / quoted-string ) - - quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE - qdtext = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text - quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) - obs-text = %x80-FF - - Example: - chunked;a=b;i=j,gzip;windowBits=12 - x,y + param-list = *( OWS ";" OWS param ) + param = token OWS [ "=" OWS ( token / quoted-string ) ] + quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE + qdtext = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text + quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text ) + obs-text = %x80-FF */ auto const err = [&] { - it = begin; + it = first; }; v.first.clear(); v.second.clear(); - detail::skip_ows(it, end); - begin = it; - if(it == end) + detail::skip_ows(it, last); + first = it; + if(it == last) return err(); if(*it != ';') return err(); ++it; - detail::skip_ows(it, end); - if(it == end) + detail::skip_ows(it, last); + if(it == last) return err(); // param if(! detail::is_tchar(*it)) return err(); auto const p0 = it; - for(;;) - { - ++it; - if(it == end) - return err(); - if(! detail::is_tchar(*it)) - break; - } + skip_token(++it, last); auto const p1 = it; - detail::skip_ows(it, end); - if(it == end) - return err(); + v.first = { &*p0, static_cast(p1 - p0) }; + detail::skip_ows(it, last); + if(it == last) + return; + if(*it == ';') + return; if(*it != '=') return err(); ++it; - detail::skip_ows(it, end); - if(it == end) - return err(); + detail::skip_ows(it, last); + if(it == last) + return; if(*it == '"') { // quoted-string @@ -339,7 +336,7 @@ increment() ++it; for(;;) { - if(it == end) + if(it == last) return err(); auto c = *it++; if(c == '"') @@ -348,13 +345,12 @@ increment() continue; if(c != '\\') return err(); - if(it == end) + if(it == last) return err(); c = *it++; if(! detail::is_qpchar(c)) return err(); } - v.first = { &*p0, static_cast(p1 - p0) }; v.second = { &*p2, static_cast(it - p2) }; } else @@ -363,15 +359,7 @@ increment() if(! detail::is_tchar(*it)) return err(); auto const p2 = it; - for(;;) - { - it++; - if(it == end) - break; - if(! detail::is_tchar(*it)) - break; - } - v.first = { &*p0, static_cast(p1 - p0) }; + skip_token(++it, last); v.second = { &*p2, static_cast(it - p2) }; } } diff --git a/include/beast/http/empty_body.hpp b/include/beast/http/empty_body.hpp index 152a71fe3..e497b87f2 100644 --- a/include/beast/http/empty_body.hpp +++ b/include/beast/http/empty_body.hpp @@ -8,8 +8,12 @@ #ifndef BEAST_HTTP_EMPTY_BODY_HPP #define BEAST_HTTP_EMPTY_BODY_HPP -#include +#include +#include +#include +#include #include +#include #include #include @@ -35,31 +39,31 @@ private: struct writer { - writer(writer const&) = delete; - writer& operator=(writer const&) = delete; - - template + template explicit - writer(message const& m) + writer(message const& m) noexcept { + beast::detail::ignore_unused(m); } void - init(error_code& ec) + init(error_code& ec) noexcept { + beast::detail::ignore_unused(ec); } std::uint64_t - content_length() const + content_length() const noexcept { return 0; } - template + template boost::tribool - operator()(resume_context&&, error_code&, Write&& write) + write(resume_context&&, error_code&, + WriteFunction&& wf) noexcept { - write(boost::asio::null_buffers{}); + wf(boost::asio::null_buffers{}); return true; } }; diff --git a/include/beast/http/headers.hpp b/include/beast/http/fields.hpp similarity index 62% rename from include/beast/http/headers.hpp rename to include/beast/http/fields.hpp index 3268fa50b..fb80ad7f1 100644 --- a/include/beast/http/headers.hpp +++ b/include/beast/http/fields.hpp @@ -5,17 +5,18 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_HTTP_HEADERS_HPP -#define BEAST_HTTP_HEADERS_HPP +#ifndef BEAST_HTTP_FIELDS_HPP +#define BEAST_HTTP_FIELDS_HPP -#include +#include #include namespace beast { namespace http { -using headers = - basic_headers>; +/// A typical HTTP header fields container +using fields = + basic_fields>; } // http } // beast diff --git a/include/beast/http/header_parser_v1.hpp b/include/beast/http/header_parser_v1.hpp new file mode 100644 index 000000000..9caafa44e --- /dev/null +++ b/include/beast/http/header_parser_v1.hpp @@ -0,0 +1,232 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_HTTP_HEADERS_PARSER_V1_HPP +#define BEAST_HTTP_HEADERS_PARSER_V1_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace http { + +namespace detail { + +struct request_parser_base +{ + std::string method_; + std::string uri_; +}; + +struct response_parser_base +{ + std::string reason_; +}; + +} // detail + +/** A parser for a HTTP/1 request or response header. + + This class uses the HTTP/1 wire format parser to + convert a series of octets into a request or + response @ref header. + + @note A new instance of the parser is required for each message. +*/ +template +class header_parser_v1 + : public basic_parser_v1> + , private std::conditional::type +{ +public: + /// The type of the header this parser produces. + using header_type = header; + +private: + // VFALCO Check Fields requirements? + + std::string field_; + std::string value_; + header_type h_; + bool flush_ = false; + +public: + /// Default constructor + header_parser_v1() = default; + + /// Move constructor + header_parser_v1(header_parser_v1&&) = default; + + /// Copy constructor (disallowed) + header_parser_v1(header_parser_v1 const&) = delete; + + /// Move assignment (disallowed) + header_parser_v1& operator=(header_parser_v1&&) = delete; + + /// Copy assignment (disallowed) + header_parser_v1& operator=(header_parser_v1 const&) = delete; + + /** Construct the parser. + + @param args Forwarded to the header constructor. + */ +#if GENERATING_DOCS + template + explicit + header_parser_v1(Args&&... args); +#else + template::type, header_parser_v1>::value>> + explicit + header_parser_v1(Arg1&& arg1, ArgN&&... argn) + : h_(std::forward(arg1), + std::forward(argn)...) + { + } +#endif + + /** Returns the parsed header + + Only valid if @ref complete would return `true`. + */ + header_type const& + get() const + { + return h_; + } + + /** Returns the parsed header. + + Only valid if @ref complete would return `true`. + */ + header_type& + get() + { + return h_; + } + + /** Returns ownership of the parsed header. + + Ownership is transferred to the caller. Only + valid if @ref complete would return `true`. + + Requires: + @ref header_type is @b MoveConstructible + */ + header_type + release() + { + static_assert(std::is_move_constructible::value, + "MoveConstructible requirements not met"); + return std::move(h_); + } + +private: + friend class basic_parser_v1; + + void flush() + { + if(! flush_) + return; + flush_ = false; + BOOST_ASSERT(! field_.empty()); + h_.fields.insert(field_, value_); + field_.clear(); + value_.clear(); + } + + void on_start(error_code&) + { + } + + void on_method(boost::string_ref const& s, error_code&) + { + this->method_.append(s.data(), s.size()); + } + + void on_uri(boost::string_ref const& s, error_code&) + { + this->uri_.append(s.data(), s.size()); + } + + void on_reason(boost::string_ref const& s, error_code&) + { + this->reason_.append(s.data(), s.size()); + } + + void on_request_or_response(std::true_type) + { + h_.method = std::move(this->method_); + h_.url = std::move(this->uri_); + } + + void on_request_or_response(std::false_type) + { + h_.status = this->status_code(); + h_.reason = std::move(this->reason_); + } + + void on_request(error_code& ec) + { + on_request_or_response( + std::integral_constant{}); + } + + void on_response(error_code& ec) + { + on_request_or_response( + std::integral_constant{}); + } + + void on_field(boost::string_ref const& s, error_code&) + { + flush(); + field_.append(s.data(), s.size()); + } + + void on_value(boost::string_ref const& s, error_code&) + { + value_.append(s.data(), s.size()); + flush_ = true; + } + + void + on_header(std::uint64_t, error_code&) + { + flush(); + h_.version = 10 * this->http_major() + this->http_minor(); + } + + body_what + on_body_what(std::uint64_t, error_code&) + { + return body_what::pause; + } + + void on_body(boost::string_ref const&, error_code&) + { + } + + void on_complete(error_code&) + { + } +}; + +} // http +} // beast + +#endif diff --git a/include/beast/http/impl/basic_headers.ipp b/include/beast/http/impl/basic_fields.ipp similarity index 70% rename from include/beast/http/impl/basic_headers.ipp rename to include/beast/http/impl/basic_fields.ipp index 206ed5759..8c421e9ef 100644 --- a/include/beast/http/impl/basic_headers.ipp +++ b/include/beast/http/impl/basic_fields.ipp @@ -5,8 +5,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_HTTP_IMPL_BASIC_HEADERS_IPP -#define BEAST_HTTP_IMPL_BASIC_HEADERS_IPP +#ifndef BEAST_HTTP_IMPL_BASIC_FIELDS_IPP +#define BEAST_HTTP_IMPL_BASIC_FIELDS_IPP #include #include @@ -14,47 +14,9 @@ namespace beast { namespace http { -namespace detail { - -inline -auto -basic_headers_base::begin() const -> - const_iterator -{ - return list_.cbegin(); -} - -inline -auto -basic_headers_base::end() const -> - const_iterator -{ - return list_.cend(); -} - -inline -auto -basic_headers_base::cbegin() const -> - const_iterator -{ - return list_.cbegin(); -} - -inline -auto -basic_headers_base::cend() const -> - const_iterator -{ - return list_.cend(); -} - -} // detail - -//------------------------------------------------------------------------------ - template void -basic_headers:: +basic_fields:: delete_all() { for(auto it = list_.begin(); it != list_.end();) @@ -69,8 +31,8 @@ delete_all() template inline void -basic_headers:: -move_assign(basic_headers& other, std::false_type) +basic_fields:: +move_assign(basic_fields& other, std::false_type) { if(this->member() != other.member()) { @@ -87,8 +49,8 @@ move_assign(basic_headers& other, std::false_type) template inline void -basic_headers:: -move_assign(basic_headers& other, std::true_type) +basic_fields:: +move_assign(basic_fields& other, std::true_type) { this->member() = std::move(other.member()); set_ = std::move(other.set_); @@ -98,8 +60,8 @@ move_assign(basic_headers& other, std::true_type) template inline void -basic_headers:: -copy_assign(basic_headers const& other, std::false_type) +basic_fields:: +copy_assign(basic_fields const& other, std::false_type) { copy_from(other); } @@ -107,8 +69,8 @@ copy_assign(basic_headers const& other, std::false_type) template inline void -basic_headers:: -copy_assign(basic_headers const& other, std::true_type) +basic_fields:: +copy_assign(basic_fields const& other, std::true_type) { this->member() = other.member(); copy_from(other); @@ -117,35 +79,35 @@ copy_assign(basic_headers const& other, std::true_type) //------------------------------------------------------------------------------ template -basic_headers:: -~basic_headers() +basic_fields:: +~basic_fields() { delete_all(); } template -basic_headers:: -basic_headers(Allocator const& alloc) +basic_fields:: +basic_fields(Allocator const& alloc) : beast::detail::empty_base_optimization< alloc_type>(alloc) { } template -basic_headers:: -basic_headers(basic_headers&& other) +basic_fields:: +basic_fields(basic_fields&& other) : beast::detail::empty_base_optimization( std::move(other.member())) - , detail::basic_headers_base( + , detail::basic_fields_base( std::move(other.set_), std::move(other.list_)) { } template auto -basic_headers:: -operator=(basic_headers&& other) -> - basic_headers& +basic_fields:: +operator=(basic_fields&& other) -> + basic_fields& { if(this == &other) return *this; @@ -156,9 +118,9 @@ operator=(basic_headers&& other) -> } template -basic_headers:: -basic_headers(basic_headers const& other) - : basic_headers(alloc_traits:: +basic_fields:: +basic_fields(basic_fields const& other) + : basic_fields(alloc_traits:: select_on_container_copy_construction(other.member())) { copy_from(other); @@ -166,9 +128,9 @@ basic_headers(basic_headers const& other) template auto -basic_headers:: -operator=(basic_headers const& other) -> - basic_headers& +basic_fields:: +operator=(basic_fields const& other) -> + basic_fields& { clear(); copy_assign(other, std::integral_constant template template -basic_headers:: -basic_headers(basic_headers const& other) +basic_fields:: +basic_fields(basic_fields const& other) { copy_from(other); } @@ -187,9 +149,9 @@ basic_headers(basic_headers const& other) template template auto -basic_headers:: -operator=(basic_headers const& other) -> - basic_headers& +basic_fields:: +operator=(basic_fields const& other) -> + basic_fields& { clear(); copy_from(other); @@ -198,8 +160,8 @@ operator=(basic_headers const& other) -> template template -basic_headers:: -basic_headers(FwdIt first, FwdIt last) +basic_fields:: +basic_fields(FwdIt first, FwdIt last) { for(;first != last; ++first) insert(first->name(), first->value()); @@ -207,7 +169,7 @@ basic_headers(FwdIt first, FwdIt last) template std::size_t -basic_headers:: +basic_fields:: count(boost::string_ref const& name) const { auto const it = set_.find(name, less{}); @@ -219,7 +181,7 @@ count(boost::string_ref const& name) const template auto -basic_headers:: +basic_fields:: find(boost::string_ref const& name) const -> iterator { @@ -231,7 +193,7 @@ find(boost::string_ref const& name) const -> template boost::string_ref -basic_headers:: +basic_fields:: operator[](boost::string_ref const& name) const { auto const it = find(name); @@ -242,7 +204,7 @@ operator[](boost::string_ref const& name) const template void -basic_headers:: +basic_fields:: clear() noexcept { delete_all(); @@ -252,7 +214,7 @@ clear() noexcept template std::size_t -basic_headers:: +basic_fields:: erase(boost::string_ref const& name) { auto it = set_.find(name, less{}); @@ -276,7 +238,7 @@ erase(boost::string_ref const& name) template void -basic_headers:: +basic_fields:: insert(boost::string_ref const& name, boost::string_ref value) { @@ -289,7 +251,7 @@ insert(boost::string_ref const& name, template void -basic_headers:: +basic_fields:: replace(boost::string_ref const& name, boost::string_ref value) { diff --git a/include/beast/http/impl/basic_parser_v1.ipp b/include/beast/http/impl/basic_parser_v1.ipp index 918c52cfe..9757b92a1 100644 --- a/include/beast/http/impl/basic_parser_v1.ipp +++ b/include/beast/http/impl/basic_parser_v1.ipp @@ -5,6 +5,16 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // +#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP +#define BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP + +#include +#include +#include + +namespace beast { +namespace http { + /* Based on src/http/ngx_http_parse.c from NGINX copyright Igor Sysoev * * Additional changes are licensed under the same terms as NGINX and @@ -28,21 +38,10 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ -/* - This code is a modified version of nodejs/http-parser, copyright above: - https://github.com/nodejs/http-parser +/* This code is a modified version of nodejs/http-parser, copyright above: + https://github.com/nodejs/http-parser */ -#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP -#define BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP - -#include -#include -#include - -namespace beast { -namespace http { - template basic_parser_v1:: basic_parser_v1() @@ -50,6 +49,55 @@ basic_parser_v1() init(); } +template +template +basic_parser_v1:: +basic_parser_v1(basic_parser_v1< + isRequest, OtherDerived> const& other) + : h_max_(other.h_max_) + , h_left_(other.h_left_) + , b_max_(other.b_max_) + , b_left_(other.b_left_) + , content_length_(other.content_length_) + , cb_(nullptr) + , s_(other.s_) + , flags_(other.flags_) + , fs_(other.fs_) + , pos_(other.pos_) + , http_major_(other.http_major_) + , http_minor_(other.http_minor_) + , status_code_(other.status_code_) + , upgrade_(other.upgrade_) +{ + BOOST_ASSERT(! other.cb_); +} + +template +template +auto +basic_parser_v1:: +operator=(basic_parser_v1< + isRequest, OtherDerived> const& other) -> + basic_parser_v1& +{ + BOOST_ASSERT(! other.cb_); + h_max_ = other.h_max_; + h_left_ = other.h_left_; + b_max_ = other.b_max_; + b_left_ = other.b_left_; + content_length_ = other.content_length_; + cb_ = nullptr; + s_ = other.s_; + flags_ = other.flags_; + fs_ = other.fs_; + pos_ = other.pos_; + http_major_ = other.http_major_; + http_minor_ = other.http_minor_; + status_code_ = other.status_code_; + upgrade_ = other.upgrade_; + return *this; +} + template bool basic_parser_v1:: @@ -170,7 +218,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec) call_on_start(ec); if(ec) return errc(); - assert(! cb_); + BOOST_ASSERT(! cb_); cb(&self::call_on_method); s_ = s_req_method; break; @@ -194,7 +242,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec) // VFALCO TODO Better checking for valid URL characters if(! is_text(ch)) return err(parse_error::bad_uri); - assert(! cb_); + BOOST_ASSERT(! cb_); cb(&self::call_on_uri); s_ = s_req_url; break; @@ -377,7 +425,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec) } if(! is_text(ch)) return err(parse_error::bad_reason); - assert(! cb_); + BOOST_ASSERT(! cb_); cb(&self::call_on_reason); s_ = s_res_reason; break; @@ -429,7 +477,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec) fs_ = h_general; break; } - assert(! cb_); + BOOST_ASSERT(! cb_); cb(&self::call_on_field); s_ = s_header_name; break; @@ -549,7 +597,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec) content_length_ = 0; flags_ |= parse_flag::contentlength; } - assert(! cb_); + BOOST_ASSERT(! cb_); cb(&self::call_on_value); s_ = s_header_value; // fall through @@ -801,7 +849,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec) return err(parse_error::bad_content_length); if(fs_ == h_upgrade) flags_ |= parse_flag::upgrade; - assert(! cb_); + BOOST_ASSERT(! cb_); call_on_value(ec, boost::string_ref{"", 0}); if(ec) return errc(); @@ -880,7 +928,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec) goto redo; case s_header_value_unfold: - assert(! cb_); + BOOST_ASSERT(! cb_); cb(&self::call_on_value); s_ = s_header_value; goto redo; @@ -899,30 +947,57 @@ write(boost::asio::const_buffer const& buffer, error_code& ec) return err(parse_error::illegal_content_length); upgrade_ = ((flags_ & (parse_flag::upgrade | parse_flag::connection_upgrade)) == (parse_flag::upgrade | parse_flag::connection_upgrade)) /*|| method == "connect"*/; - auto const maybe_skip = call_on_headers(ec); + call_on_headers(ec); if(ec) return errc(); - switch(maybe_skip) + auto const what = call_on_body_what(ec); + if(ec) + return errc(); + switch(what) { - case 0: + case body_what::normal: break; - case 2: + case body_what::upgrade: upgrade_ = true; // fall through - case 1: + case body_what::skip: flags_ |= parse_flag::skipbody; break; - default: - return err(parse_error::bad_on_headers_rv); + case body_what::pause: + ++p; + s_ = s_body_pause; + return used(); } s_ = s_headers_done; goto redo; } + case s_body_pause: + { + auto const what = call_on_body_what(ec); + if(ec) + return errc(); + switch(what) + { + case body_what::normal: + break; + case body_what::upgrade: + upgrade_ = true; + // fall through + case body_what::skip: + flags_ |= parse_flag::skipbody; + break; + case body_what::pause: + return used(); + } + --p; + s_ = s_headers_done; + // fall through + } + case s_headers_done: { - assert(! cb_); - call_on_headers(ec); + BOOST_ASSERT(! cb_); if(ec) return errc(); bool const hasBody = @@ -959,7 +1034,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec) } case s_body_identity0: - assert(! cb_); + BOOST_ASSERT(! cb_); cb(&self::call_on_body); s_ = s_body_identity; // fall through @@ -971,7 +1046,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec) n = end - p; else n = static_cast(content_length_); - assert(content_length_ != 0 && content_length_ != no_content_length); + BOOST_ASSERT(content_length_ != 0 && content_length_ != no_content_length); content_length_ -= n; if(content_length_ == 0) { @@ -984,7 +1059,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec) } case s_body_identity_eof0: - assert(! cb_); + BOOST_ASSERT(! cb_); cb(&self::call_on_body); s_ = s_body_identity_eof; // fall through @@ -1073,7 +1148,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec) break; case s_chunk_data0: - assert(! cb_); + BOOST_ASSERT(! cb_); cb(&self::call_on_body); s_ = s_chunk_data; goto redo; // VFALCO fall through? @@ -1167,6 +1242,17 @@ write_eof(error_code& ec) } } +template +void +basic_parser_v1:: +reset() +{ + cb_ = nullptr; + h_left_ = h_max_; + b_left_ = b_max_; + reset(std::integral_constant{}); +} + template bool basic_parser_v1:: diff --git a/include/beast/http/impl/message.ipp b/include/beast/http/impl/message.ipp new file mode 100644 index 000000000..9a818cd87 --- /dev/null +++ b/include/beast/http/impl/message.ipp @@ -0,0 +1,264 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_HTTP_IMPL_MESSAGE_IPP +#define BEAST_HTTP_IMPL_MESSAGE_IPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace http { + +template +void +swap( + header& m1, + header& m2) +{ + using std::swap; + swap(m1.version, m2.version); + swap(m1.method, m2.method); + swap(m1.url, m2.url); + swap(m1.fields, m2.fields); +} + +template +void +swap( + header& a, + header& b) +{ + using std::swap; + swap(a.version, b.version); + swap(a.status, b.status); + swap(a.reason, b.reason); + swap(a.fields, b.fields); +} + +template +void +swap( + message& m1, + message& m2) +{ + using std::swap; + swap(m1.base(), m2.base()); + swap(m1.body, m2.body); +} + +template +bool +is_keep_alive(header const& msg) +{ + BOOST_ASSERT(msg.version == 10 || msg.version == 11); + if(msg.version == 11) + { + if(token_list{msg.fields["Connection"]}.exists("close")) + return false; + return true; + } + if(token_list{msg.fields["Connection"]}.exists("keep-alive")) + return true; + return false; +} + +template +bool +is_upgrade(header const& msg) +{ + BOOST_ASSERT(msg.version == 10 || msg.version == 11); + if(msg.version == 10) + return false; + if(token_list{msg.fields["Connection"]}.exists("upgrade")) + return true; + return false; +} + +namespace detail { + +struct prepare_info +{ + boost::optional connection_value; + boost::optional content_length; +}; + +template +inline +void +prepare_options(prepare_info& pi, + message& msg) +{ + beast::detail::ignore_unused(pi, msg); +} + +template +void +prepare_option(prepare_info& pi, + message& msg, + connection value) +{ + beast::detail::ignore_unused(msg); + pi.connection_value = value; +} + +template< + bool isRequest, class Body, class Fields, + class Opt, class... Opts> +void +prepare_options(prepare_info& pi, + message& msg, + Opt&& opt, Opts&&... opts) +{ + prepare_option(pi, msg, opt); + prepare_options(pi, msg, + std::forward(opts)...); +} + +template +void +prepare_content_length(prepare_info& pi, + message const& msg, + std::true_type) +{ + typename Body::writer w(msg); + // VFALCO This is a design problem! + error_code ec; + w.init(ec); + if(ec) + throw system_error{ec}; + pi.content_length = w.content_length(); +} + +template +void +prepare_content_length(prepare_info& pi, + message const& msg, + std::false_type) +{ + beast::detail::ignore_unused(msg); + pi.content_length = boost::none; +} + +} // detail + +template< + bool isRequest, class Body, class Fields, + class... Options> +void +prepare(message& msg, + Options&&... options) +{ + // VFALCO TODO + static_assert(is_Body::value, + "Body requirements not met"); + static_assert(has_writer::value, + "Body has no writer"); + static_assert(is_Writer>::value, + "Writer requirements not met"); + detail::prepare_info pi; + detail::prepare_content_length(pi, msg, + detail::has_content_length{}); + detail::prepare_options(pi, msg, + std::forward(options)...); + + if(msg.fields.exists("Connection")) + throw std::invalid_argument( + "prepare called with Connection field set"); + + if(msg.fields.exists("Content-Length")) + throw std::invalid_argument( + "prepare called with Content-Length field set"); + + if(token_list{msg.fields["Transfer-Encoding"]}.exists("chunked")) + throw std::invalid_argument( + "prepare called with Transfer-Encoding: chunked set"); + + if(pi.connection_value != connection::upgrade) + { + if(pi.content_length) + { + struct set_field + { + void + operator()(message& msg, + detail::prepare_info const& pi) const + { + using beast::detail::ci_equal; + if(*pi.content_length > 0 || + ci_equal(msg.method, "POST")) + { + msg.fields.insert( + "Content-Length", *pi.content_length); + } + } + + void + operator()(message& msg, + detail::prepare_info const& pi) const + { + if((msg.status / 100 ) != 1 && + msg.status != 204 && + msg.status != 304) + { + msg.fields.insert( + "Content-Length", *pi.content_length); + } + } + }; + set_field{}(msg, pi); + } + else if(msg.version >= 11) + { + msg.fields.insert("Transfer-Encoding", "chunked"); + } + } + + auto const content_length = + msg.fields.exists("Content-Length"); + + if(pi.connection_value) + { + switch(*pi.connection_value) + { + case connection::upgrade: + msg.fields.insert("Connection", "upgrade"); + break; + + case connection::keep_alive: + if(msg.version < 11) + { + if(content_length) + msg.fields.insert("Connection", "keep-alive"); + } + break; + + case connection::close: + if(msg.version >= 11) + msg.fields.insert("Connection", "close"); + break; + } + } + + // rfc7230 6.7. + if(msg.version < 11 && token_list{ + msg.fields["Connection"]}.exists("upgrade")) + throw std::invalid_argument( + "invalid version for Connection: upgrade"); +} + +} // http +} // beast + +#endif diff --git a/include/beast/http/impl/message_v1.ipp b/include/beast/http/impl/message_v1.ipp deleted file mode 100644 index e2a2568d8..000000000 --- a/include/beast/http/impl/message_v1.ipp +++ /dev/null @@ -1,188 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_HTTP_IMPL_MESSAGE_V1_IPP -#define BEAST_HTTP_IMPL_MESSAGE_V1_IPP - -#include -#include -#include -#include -#include - -namespace beast { -namespace http { - -template -bool -is_keep_alive(message_v1 const& msg) -{ - if(msg.version >= 11) - { - if(token_list{msg.headers["Connection"]}.exists("close")) - return false; - return true; - } - if(token_list{msg.headers["Connection"]}.exists("keep-alive")) - return true; - return false; -} - -template -bool -is_upgrade(message_v1 const& msg) -{ - if(msg.version < 11) - return false; - if(token_list{msg.headers["Connection"]}.exists("upgrade")) - return true; - return false; -} - -namespace detail { - -struct prepare_info -{ - boost::optional connection_value; - boost::optional content_length; -}; - -template -inline -void -prepare_options(prepare_info& pi, - message_v1& msg) -{ -} - -template -void -prepare_option(prepare_info& pi, - message_v1& msg, - connection value) -{ - pi.connection_value = value; -} - -template< - bool isRequest, class Body, class Headers, - class Opt, class... Opts> -void -prepare_options(prepare_info& pi, - message_v1& msg, - Opt&& opt, Opts&&... opts) -{ - prepare_option(pi, msg, opt); - prepare_options(pi, msg, - std::forward(opts)...); -} - -template -void -prepare_content_length(prepare_info& pi, - message_v1 const& msg, - std::true_type) -{ - typename Body::writer w(msg); - // VFALCO This is a design problem! - error_code ec; - w.init(ec); - if(ec) - throw system_error{ec}; - pi.content_length = w.content_length(); -} - -template -void -prepare_content_length(prepare_info& pi, - message_v1 const& msg, - std::false_type) -{ - pi.content_length = boost::none; -} - -} // detail - -template< - bool isRequest, class Body, class Headers, - class... Options> -void -prepare(message_v1& msg, - Options&&... options) -{ - // VFALCO TODO - //static_assert(is_WritableBody::value, - // "WritableBody requirements not met"); - detail::prepare_info pi; - detail::prepare_content_length(pi, msg, - detail::has_content_length{}); - detail::prepare_options(pi, msg, - std::forward(options)...); - - if(msg.headers.exists("Connection")) - throw std::invalid_argument( - "prepare called with Connection field set"); - - if(msg.headers.exists("Content-Length")) - throw std::invalid_argument( - "prepare called with Content-Length field set"); - - if(token_list{msg.headers["Transfer-Encoding"]}.exists("chunked")) - throw std::invalid_argument( - "prepare called with Transfer-Encoding: chunked set"); - - if(pi.connection_value != connection::upgrade) - { - if(pi.content_length) - { - // VFALCO TODO Use a static string here - msg.headers.insert("Content-Length", - std::to_string(*pi.content_length)); - } - else if(msg.version >= 11) - { - msg.headers.insert("Transfer-Encoding", "chunked"); - } - } - - auto const content_length = - msg.headers.exists("Content-Length"); - - if(pi.connection_value) - { - switch(*pi.connection_value) - { - case connection::upgrade: - msg.headers.insert("Connection", "upgrade"); - break; - - case connection::keep_alive: - if(msg.version < 11) - { - if(content_length) - msg.headers.insert("Connection", "keep-alive"); - } - break; - - case connection::close: - if(msg.version >= 11) - msg.headers.insert("Connection", "close"); - break; - } - } - - // rfc7230 6.7. - if(msg.version < 11 && token_list{ - msg.headers["Connection"]}.exists("upgrade")) - throw std::invalid_argument( - "invalid version for Connection: upgrade"); -} - -} // http -} // beast - -#endif diff --git a/include/beast/http/impl/parse.ipp b/include/beast/http/impl/parse.ipp new file mode 100644 index 000000000..913b41b16 --- /dev/null +++ b/include/beast/http/impl/parse.ipp @@ -0,0 +1,303 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_HTTP_IMPL_PARSE_IPP_HPP +#define BEAST_HTTP_IMPL_PARSE_IPP_HPP + +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace http { + +namespace detail { + +template +class parse_op +{ + struct data + { + bool cont; + Stream& s; + DynamicBuffer& db; + Parser& p; + bool got_some = false; + int state = 0; + + data(Handler& handler, Stream& s_, + DynamicBuffer& sb_, Parser& p_) + : cont(beast_asio_helpers:: + is_continuation(handler)) + , s(s_) + , db(sb_) + , p(p_) + { + BOOST_ASSERT(! p.complete()); + } + }; + + handler_ptr d_; + +public: + parse_op(parse_op&&) = default; + parse_op(parse_op const&) = default; + + template + parse_op(DeducedHandler&& h, Stream& s, Args&&... args) + : d_(make_handler_ptr( + std::forward(h), s, + std::forward(args)...)) + { + (*this)(error_code{}, 0, false); + } + + void + operator()(error_code ec, + std::size_t bytes_transferred, bool again = true); + + friend + void* asio_handler_allocate( + std::size_t size, parse_op* op) + { + return beast_asio_helpers:: + allocate(size, op->d_.handler()); + } + + friend + void asio_handler_deallocate( + void* p, std::size_t size, parse_op* op) + { + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); + } + + friend + bool asio_handler_is_continuation(parse_op* op) + { + return op->d_->cont; + } + + template + friend + void asio_handler_invoke(Function&& f, parse_op* op) + { + return beast_asio_helpers:: + invoke(f, op->d_.handler()); + } +}; + +template +void +parse_op:: +operator()(error_code ec, std::size_t bytes_transferred, bool again) +{ + auto& d = *d_; + d.cont = d.cont || again; + while(d.state != 99) + { + switch(d.state) + { + case 0: + { + // Parse any bytes left over in the buffer + auto const used = + d.p.write(d.db.data(), ec); + if(ec) + { + // call handler + d.state = 99; + d.s.get_io_service().post( + bind_handler(std::move(*this), ec, 0)); + return; + } + if(used > 0) + { + d.got_some = true; + d.db.consume(used); + } + if(d.p.complete()) + { + // call handler + d.state = 99; + d.s.get_io_service().post( + bind_handler(std::move(*this), ec, 0)); + return; + } + // Buffer must be empty, + // otherwise parse should be complete + BOOST_ASSERT(d.db.size() == 0); + d.state = 1; + break; + } + + case 1: + { + // read + d.state = 2; + auto const size = + read_size_helper(d.db, 65536); + BOOST_ASSERT(size > 0); + d.s.async_read_some( + d.db.prepare(size), std::move(*this)); + return; + } + + // got data + case 2: + { + if(ec == boost::asio::error::eof) + { + // If we haven't processed any bytes, + // give the eof to the handler immediately. + if(! d.got_some) + { + // call handler + d.state = 99; + break; + } + // Feed the eof to the parser to complete + // the parse, and call the handler. The + // next call to parse will deliver the eof. + ec = {}; + d.p.write_eof(ec); + BOOST_ASSERT(ec || d.p.complete()); + // call handler + d.state = 99; + break; + } + if(ec) + { + // call handler + d.state = 99; + break; + } + BOOST_ASSERT(bytes_transferred > 0); + d.db.commit(bytes_transferred); + auto const used = d.p.write(d.db.data(), ec); + if(ec) + { + // call handler + d.state = 99; + break; + } + // The parser must either consume + // bytes or generate an error. + BOOST_ASSERT(used > 0); + d.got_some = true; + d.db.consume(used); + if(d.p.complete()) + { + // call handler + d.state = 99; + break; + } + // If the parse is not complete, + // all input must be consumed. + BOOST_ASSERT(used == bytes_transferred); + d.state = 1; + break; + } + } + } + d_.invoke(ec); +} + +} // detail + +//------------------------------------------------------------------------------ + +template +void +parse(SyncReadStream& stream, + DynamicBuffer& dynabuf, Parser& parser) +{ + static_assert(is_SyncReadStream::value, + "SyncReadStream requirements not met"); + static_assert(is_DynamicBuffer::value, + "DynamicBuffer requirements not met"); + static_assert(is_Parser::value, + "Parser requirements not met"); + error_code ec; + parse(stream, dynabuf, parser, ec); + if(ec) + throw system_error{ec}; +} + +template +void +parse(SyncReadStream& stream, DynamicBuffer& dynabuf, + Parser& parser, error_code& ec) +{ + static_assert(is_SyncReadStream::value, + "SyncReadStream requirements not met"); + static_assert(is_DynamicBuffer::value, + "DynamicBuffer requirements not met"); + static_assert(is_Parser::value, + "Parser requirements not met"); + bool got_some = false; + for(;;) + { + auto used = + parser.write(dynabuf.data(), ec); + if(ec) + return; + dynabuf.consume(used); + if(used > 0) + got_some = true; + if(parser.complete()) + break; + dynabuf.commit(stream.read_some( + dynabuf.prepare(read_size_helper( + dynabuf, 65536)), ec)); + if(ec && ec != boost::asio::error::eof) + return; + if(ec == boost::asio::error::eof) + { + if(! got_some) + return; + // Caller will see eof on next read. + ec = {}; + parser.write_eof(ec); + if(ec) + return; + BOOST_ASSERT(parser.complete()); + break; + } + } +} + +template +typename async_completion< + ReadHandler, void(error_code)>::result_type +async_parse(AsyncReadStream& stream, + DynamicBuffer& dynabuf, Parser& parser, ReadHandler&& handler) +{ + static_assert(is_AsyncReadStream::value, + "AsyncReadStream requirements not met"); + static_assert(is_DynamicBuffer::value, + "DynamicBuffer requirements not met"); + static_assert(is_Parser::value, + "Parser requirements not met"); + beast::async_completion completion(handler); + detail::parse_op{ + completion.handler, stream, dynabuf, parser}; + return completion.result.get(); +} + +} // http +} // beast + +#endif diff --git a/include/beast/http/impl/parse_error.ipp b/include/beast/http/impl/parse_error.ipp new file mode 100644 index 000000000..83578ceb0 --- /dev/null +++ b/include/beast/http/impl/parse_error.ipp @@ -0,0 +1,105 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_HTTP_IMPL_PARSE_ERROR_IPP +#define BEAST_HTTP_IMPL_PARSE_ERROR_IPP + +namespace boost { +namespace system { +template<> +struct is_error_code_enum +{ + static bool const value = true; +}; +} // system +} // boost + +namespace beast { +namespace http { +namespace detail { + +class parse_error_category : public error_category +{ +public: + const char* + name() const noexcept override + { + return "http"; + } + + std::string + message(int ev) const override + { + switch(static_cast(ev)) + { + case parse_error::connection_closed: return "data after Connection close"; + case parse_error::bad_method: return "bad method"; + case parse_error::bad_uri: return "bad request-target"; + case parse_error::bad_version: return "bad HTTP-Version"; + case parse_error::bad_crlf: return "missing CRLF"; + case parse_error::bad_status: return "bad status-code"; + case parse_error::bad_reason: return "bad reason-phrase"; + case parse_error::bad_field: return "bad field token"; + case parse_error::bad_value: return "bad field-value"; + case parse_error::bad_content_length: return "bad Content-Length"; + case parse_error::illegal_content_length: return "illegal Content-Length with chunked Transfer-Encoding"; + case parse_error::invalid_chunk_size: return "invalid chunk size"; + case parse_error::invalid_ext_name: return "invalid ext name"; + case parse_error::invalid_ext_val: return "invalid ext val"; + case parse_error::header_too_big: return "header size limit exceeded"; + case parse_error::body_too_big: return "body size limit exceeded"; + default: + case parse_error::short_read: return "unexpected end of data"; + } + } + + error_condition + default_error_condition(int ev) const noexcept override + { + return error_condition{ev, *this}; + } + + bool + equivalent(int ev, + error_condition const& condition + ) const noexcept override + { + return condition.value() == ev && + &condition.category() == this; + } + + bool + equivalent(error_code const& error, int ev) const noexcept override + { + return error.value() == ev && + &error.category() == this; + } +}; + +inline +error_category const& +get_parse_error_category() +{ + static parse_error_category const cat{}; + return cat; +} + +} // detail + +inline +error_code +make_error_code(parse_error ev) +{ + return error_code{ + static_cast::type>(ev), + detail::get_parse_error_category()}; +} + +} // http +} // beast + +#endif diff --git a/include/beast/http/impl/read.ipp b/include/beast/http/impl/read.ipp index b2acc0d91..3f3961dde 100644 --- a/include/beast/http/impl/read.ipp +++ b/include/beast/http/impl/read.ipp @@ -9,243 +9,62 @@ #define BEAST_HTTP_IMPL_READ_IPP_HPP #include +#include +#include #include #include -#include +#include +#include #include -#include +#include namespace beast { namespace http { namespace detail { -template -class parse_op -{ - using alloc_type = - handler_alloc; - - struct data - { - Stream& s; - DynamicBuffer& db; - Parser& p; - Handler h; - bool started = false; - bool cont; - int state = 0; - - template - data(DeducedHandler&& h_, Stream& s_, - DynamicBuffer& sb_, Parser& p_) - : s(s_) - , db(sb_) - , p(p_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) - { - } - }; - - std::shared_ptr d_; - -public: - parse_op(parse_op&&) = default; - parse_op(parse_op const&) = default; - - template - parse_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, - std::forward(h), s, - std::forward(args)...)) - { - (*this)(error_code{}, 0, false); - } - - void - operator()(error_code ec, - std::size_t bytes_transferred, bool again = true); - - friend - void* asio_handler_allocate( - std::size_t size, parse_op* op) - { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); - } - - friend - void asio_handler_deallocate( - void* p, std::size_t size, parse_op* op) - { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); - } - - friend - bool asio_handler_is_continuation(parse_op* op) - { - return op->d_->cont; - } - - template - friend - void asio_handler_invoke(Function&& f, parse_op* op) - { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); - } -}; - -template -void -parse_op:: -operator()(error_code ec, std::size_t bytes_transferred, bool again) -{ - auto& d = *d_; - d.cont = d.cont || again; - while(d.state != 99) - { - switch(d.state) - { - case 0: - { - auto const used = - d.p.write(d.db.data(), ec); - if(ec) - { - // call handler - d.state = 99; - d.s.get_io_service().post( - bind_handler(std::move(*this), ec, 0)); - return; - } - if(used > 0) - d.started = true; - d.db.consume(used); - if(d.p.complete()) - { - // call handler - d.state = 99; - d.s.get_io_service().post( - bind_handler(std::move(*this), ec, 0)); - return; - } - d.state = 1; - break; - } - - case 1: - // read - d.state = 2; - d.s.async_read_some(d.db.prepare( - read_size_helper(d.db, 65536)), - std::move(*this)); - return; - - // got data - case 2: - { - if(ec == boost::asio::error::eof) - { - if(! d.started) - { - // call handler - d.state = 99; - break; - } - // Caller will see eof on next read. - ec = {}; - d.p.write_eof(ec); - assert(ec || d.p.complete()); - // call handler - d.state = 99; - break; - } - if(ec) - { - // call handler - d.state = 99; - break; - } - d.db.commit(bytes_transferred); - auto const used = d.p.write(d.db.data(), ec); - if(ec) - { - // call handler - d.state = 99; - break; - } - if(used > 0) - d.started = true; - d.db.consume(used); - if(d.p.complete()) - { - // call handler - d.state = 99; - break; - } - d.state = 1; - break; - } - } - } - d.h(ec); -} - -//------------------------------------------------------------------------------ - template -class read_op +class read_header_op { - using alloc_type = - handler_alloc; - using parser_type = - parser_v1; + header_parser_v1; using message_type = - message_v1; + header; struct data { + bool cont; Stream& s; DynamicBuffer& db; message_type& m; parser_type p; - Handler h; bool started = false; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, Stream& s_, + data(Handler& handler, Stream& s_, DynamicBuffer& sb_, message_type& m_) - : s(s_) + : cont(beast_asio_helpers:: + is_continuation(handler)) + , s(s_) , db(sb_) , m(m_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: - read_op(read_op&&) = default; - read_op(read_op const&) = default; + read_header_op(read_header_op&&) = default; + read_header_op(read_header_op const&) = default; template - read_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + read_header_op( + DeducedHandler&& h, Stream& s, Args&&... args) + : d_(make_handler_ptr( std::forward(h), s, std::forward(args)...)) { @@ -257,40 +76,40 @@ public: friend void* asio_handler_allocate( - std::size_t size, read_op* op) + std::size_t size, read_header_op* op) { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + return beast_asio_helpers:: + allocate(size, op->d_.handler()); } friend void asio_handler_deallocate( - void* p, std::size_t size, read_op* op) + void* p, std::size_t size, read_header_op* op) { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); } friend - bool asio_handler_is_continuation(read_op* op) + bool asio_handler_is_continuation(read_header_op* op) { return op->d_->cont; } template friend - void asio_handler_invoke(Function&& f, read_op* op) + void asio_handler_invoke(Function&& f, read_header_op* op) { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + return beast_asio_helpers:: + invoke(f, op->d_.handler()); } }; template void -read_op:: +read_header_op:: operator()(error_code ec, bool again) { auto& d = *d_; @@ -311,106 +130,21 @@ operator()(error_code ec, bool again) break; } } - d.h(ec); + d_.invoke(ec); } } // detail -//------------------------------------------------------------------------------ - -template -void -parse(SyncReadStream& stream, - DynamicBuffer& dynabuf, Parser& parser) -{ - static_assert(is_SyncReadStream::value, - "SyncReadStream requirements not met"); - static_assert(is_DynamicBuffer::value, - "DynamicBuffer requirements not met"); - static_assert(is_Parser::value, - "Parser requirements not met"); - error_code ec; - parse(stream, dynabuf, parser, ec); - if(ec) - throw boost::system::system_error{ec}; -} - -template -void -parse(SyncReadStream& stream, DynamicBuffer& dynabuf, - Parser& parser, error_code& ec) -{ - static_assert(is_SyncReadStream::value, - "SyncReadStream requirements not met"); - static_assert(is_DynamicBuffer::value, - "DynamicBuffer requirements not met"); - static_assert(is_Parser::value, - "Parser requirements not met"); - bool started = false; - for(;;) - { - auto used = - parser.write(dynabuf.data(), ec); - if(ec) - return; - dynabuf.consume(used); - if(used > 0) - started = true; - if(parser.complete()) - break; - dynabuf.commit(stream.read_some( - dynabuf.prepare(read_size_helper( - dynabuf, 65536)), ec)); - if(ec && ec != boost::asio::error::eof) - return; - if(ec == boost::asio::error::eof) - { - if(! started) - return; - // Caller will see eof on next read. - ec = {}; - parser.write_eof(ec); - if(ec) - return; - assert(parser.complete()); - break; - } - } -} - -template -typename async_completion< - ReadHandler, void(error_code)>::result_type -async_parse(AsyncReadStream& stream, - DynamicBuffer& dynabuf, Parser& parser, ReadHandler&& handler) -{ - static_assert(is_AsyncReadStream::value, - "AsyncReadStream requirements not met"); - static_assert(is_DynamicBuffer::value, - "DynamicBuffer requirements not met"); - static_assert(is_Parser::value, - "Parser requirements not met"); - beast::async_completion completion(handler); - detail::parse_op{ - completion.handler, stream, dynabuf, parser}; - return completion.result.get(); -} - template + bool isRequest, class Fields> void read(SyncReadStream& stream, DynamicBuffer& dynabuf, - message_v1& msg) + header& msg) { static_assert(is_SyncReadStream::value, "SyncReadStream requirements not met"); static_assert(is_DynamicBuffer::value, "DynamicBuffer requirements not met"); - static_assert(is_ReadableBody::value, - "ReadableBody requirements not met"); error_code ec; beast::http::read(stream, dynabuf, msg, ec); if(ec) @@ -418,45 +152,234 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf, } template + bool isRequest, class Fields> void read(SyncReadStream& stream, DynamicBuffer& dynabuf, - message_v1& m, + header& m, error_code& ec) { static_assert(is_SyncReadStream::value, "SyncReadStream requirements not met"); static_assert(is_DynamicBuffer::value, "DynamicBuffer requirements not met"); - static_assert(is_ReadableBody::value, - "ReadableBody requirements not met"); - parser_v1 p; + header_parser_v1 p; beast::http::parse(stream, dynabuf, p, ec); if(ec) return; - assert(p.complete()); + BOOST_ASSERT(p.complete()); m = p.release(); } template typename async_completion< ReadHandler, void(error_code)>::result_type async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf, - message_v1& m, + header& m, ReadHandler&& handler) { static_assert(is_AsyncReadStream::value, "AsyncReadStream requirements not met"); static_assert(is_DynamicBuffer::value, "DynamicBuffer requirements not met"); - static_assert(is_ReadableBody::value, - "ReadableBody requirements not met"); + beast::async_completion completion(handler); + detail::read_header_op{completion.handler, + stream, dynabuf, m}; + return completion.result.get(); +} + +//------------------------------------------------------------------------------ + +namespace detail { + +template +class read_op +{ + using parser_type = + parser_v1; + + using message_type = + message; + + struct data + { + bool cont; + Stream& s; + DynamicBuffer& db; + message_type& m; + parser_type p; + bool started = false; + int state = 0; + + data(Handler& handler, Stream& s_, + DynamicBuffer& sb_, message_type& m_) + : cont(beast_asio_helpers:: + is_continuation(handler)) + , s(s_) + , db(sb_) + , m(m_) + { + } + }; + + handler_ptr d_; + +public: + read_op(read_op&&) = default; + read_op(read_op const&) = default; + + template + read_op(DeducedHandler&& h, Stream& s, Args&&... args) + : d_(make_handler_ptr( + std::forward(h), s, + std::forward(args)...)) + { + (*this)(error_code{}, false); + } + + void + operator()(error_code ec, bool again = true); + + friend + void* asio_handler_allocate( + std::size_t size, read_op* op) + { + return beast_asio_helpers:: + allocate(size, op->d_.handler()); + } + + friend + void asio_handler_deallocate( + void* p, std::size_t size, read_op* op) + { + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); + } + + friend + bool asio_handler_is_continuation(read_op* op) + { + return op->d_->cont; + } + + template + friend + void asio_handler_invoke(Function&& f, read_op* op) + { + return beast_asio_helpers:: + invoke(f, op->d_.handler()); + } +}; + +template +void +read_op:: +operator()(error_code ec, bool again) +{ + auto& d = *d_; + d.cont = d.cont || again; + while(! ec && d.state != 99) + { + switch(d.state) + { + case 0: + d.state = 1; + async_parse(d.s, d.db, d.p, std::move(*this)); + return; + + case 1: + // call handler + d.state = 99; + d.m = d.p.release(); + break; + } + } + d_.invoke(ec); +} + +} // detail + +template +void +read(SyncReadStream& stream, DynamicBuffer& dynabuf, + message& msg) +{ + static_assert(is_SyncReadStream::value, + "SyncReadStream requirements not met"); + static_assert(is_DynamicBuffer::value, + "DynamicBuffer requirements not met"); + static_assert(is_Body::value, + "Body requirements not met"); + static_assert(has_reader::value, + "Body has no reader"); + static_assert(is_Reader>::value, + "Reader requirements not met"); + error_code ec; + beast::http::read(stream, dynabuf, msg, ec); + if(ec) + throw system_error{ec}; +} + +template +void +read(SyncReadStream& stream, DynamicBuffer& dynabuf, + message& m, + error_code& ec) +{ + static_assert(is_SyncReadStream::value, + "SyncReadStream requirements not met"); + static_assert(is_DynamicBuffer::value, + "DynamicBuffer requirements not met"); + static_assert(is_Body::value, + "Body requirements not met"); + static_assert(has_reader::value, + "Body has no reader"); + static_assert(is_Reader>::value, + "Reader requirements not met"); + parser_v1 p; + beast::http::parse(stream, dynabuf, p, ec); + if(ec) + return; + BOOST_ASSERT(p.complete()); + m = p.release(); +} + +template +typename async_completion< + ReadHandler, void(error_code)>::result_type +async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf, + message& m, + ReadHandler&& handler) +{ + static_assert(is_AsyncReadStream::value, + "AsyncReadStream requirements not met"); + static_assert(is_DynamicBuffer::value, + "DynamicBuffer requirements not met"); + static_assert(is_Body::value, + "Body requirements not met"); + static_assert(has_reader::value, + "Body has no reader"); + static_assert(is_Reader>::value, + "Reader requirements not met"); beast::async_completion completion(handler); detail::read_op{completion.handler, stream, dynabuf, m}; return completion.result.get(); diff --git a/include/beast/http/impl/rfc7230.ipp b/include/beast/http/impl/rfc7230.ipp index feffa23ee..4de3a0fa5 100644 --- a/include/beast/http/impl/rfc7230.ipp +++ b/include/beast/http/impl/rfc7230.ipp @@ -36,8 +36,8 @@ public: { return other.pi_.it == pi_.it && - other.pi_.end == pi_.end && - other.pi_.begin == pi_.begin; + other.pi_.last == pi_.last && + other.pi_.first == pi_.first; } bool @@ -76,11 +76,11 @@ public: private: friend class param_list; - const_iterator(iter_type begin, iter_type end) + const_iterator(iter_type first, iter_type last) { - pi_.it = begin; - pi_.begin = begin; - pi_.end = end; + pi_.it = first; + pi_.first = first; + pi_.last = last; increment(); } @@ -158,10 +158,11 @@ increment() pi_.increment(); if(pi_.empty()) { - pi_.it = pi_.end; - pi_.begin = pi_.end; + pi_.it = pi_.last; + pi_.first = pi_.last; } - else if(pi_.v.second.front() == '"') + else if(! pi_.v.second.empty() && + pi_.v.second.front() == '"') { s_ = unquote(pi_.v.second); pi_.v.second = boost::string_ref{ @@ -175,8 +176,8 @@ class ext_list::const_iterator { ext_list::value_type v_; iter_type it_; - iter_type begin_; - iter_type end_; + iter_type first_; + iter_type last_; public: using value_type = ext_list::value_type; @@ -192,8 +193,8 @@ public: { return other.it_ == it_ && - other.begin_ == begin_ && - other.end_ == end_; + other.first_ == first_ && + other.last_ == last_; } bool @@ -235,8 +236,8 @@ private: const_iterator(iter_type begin, iter_type end) { it_ = begin; - begin_ = begin; - end_ = end; + first_ = begin; + last_ = end; increment(); } @@ -320,16 +321,16 @@ increment() auto const err = [&] { - it_ = end_; - begin_ = end_; + it_ = last_; + first_ = last_; }; - auto need_comma = it_ != begin_; + auto need_comma = it_ != first_; v_.first = {}; - begin_ = it_; + first_ = it_; for(;;) { - detail::skip_ows(it_, end_); - if(it_ == end_) + detail::skip_ows(it_, last_); + if(it_ == last_) return err(); auto const c = *it_; if(detail::is_tchar(c)) @@ -340,7 +341,7 @@ increment() for(;;) { ++it_; - if(it_ == end_) + if(it_ == last_) break; if(! detail::is_tchar(*it_)) break; @@ -349,8 +350,8 @@ increment() static_cast(it_ - p0)}; detail::param_iter pi; pi.it = it_; - pi.begin = it_; - pi.end = end_; + pi.first = it_; + pi.last = last_; for(;;) { pi.increment(); @@ -375,8 +376,8 @@ class token_list::const_iterator { token_list::value_type v_; iter_type it_; - iter_type begin_; - iter_type end_; + iter_type first_; + iter_type last_; public: using value_type = token_list::value_type; @@ -392,8 +393,8 @@ public: { return other.it_ == it_ && - other.begin_ == begin_ && - other.end_ == end_; + other.first_ == first_ && + other.last_ == last_; } bool @@ -435,8 +436,8 @@ private: const_iterator(iter_type begin, iter_type end) { it_ = begin; - begin_ = begin; - end_ = end; + first_ = begin; + last_ = end; increment(); } @@ -492,16 +493,16 @@ increment() auto const err = [&] { - it_ = end_; - begin_ = end_; + it_ = last_; + first_ = last_; }; - auto need_comma = it_ != begin_; + auto need_comma = it_ != first_; v_ = {}; - begin_ = it_; + first_ = it_; for(;;) { - detail::skip_ows(it_, end_); - if(it_ == end_) + detail::skip_ows(it_, last_); + if(it_ == last_) return err(); auto const c = *it_; if(detail::is_tchar(c)) @@ -512,7 +513,7 @@ increment() for(;;) { ++it_; - if(it_ == end_) + if(it_ == last_) break; if(! detail::is_tchar(*it_)) break; diff --git a/include/beast/http/impl/write.ipp b/include/beast/http/impl/write.ipp index 64f7a98d2..c2f710436 100644 --- a/include/beast/http/impl/write.ipp +++ b/include/beast/http/impl/write.ipp @@ -10,15 +10,16 @@ #include #include -#include -#include +#include #include #include #include -#include +#include +#include #include #include #include +#include #include #include #include @@ -32,31 +33,41 @@ namespace http { namespace detail { -template +template void -write_firstline(DynamicBuffer& dynabuf, - message_v1 const& msg) +write_start_line(DynamicBuffer& dynabuf, + header const& msg) { + BOOST_ASSERT(msg.version == 10 || msg.version == 11); write(dynabuf, msg.method); write(dynabuf, " "); write(dynabuf, msg.url); - write(dynabuf, " HTTP/"); - write(dynabuf, msg.version / 10); - write(dynabuf, "."); - write(dynabuf, msg.version % 10); - write(dynabuf, "\r\n"); + switch(msg.version) + { + case 10: + write(dynabuf, " HTTP/1.0\r\n"); + break; + case 11: + write(dynabuf, " HTTP/1.1\r\n"); + break; + } } -template +template void -write_firstline(DynamicBuffer& dynabuf, - message_v1 const& msg) +write_start_line(DynamicBuffer& dynabuf, + header const& msg) { - write(dynabuf, "HTTP/"); - write(dynabuf, msg.version / 10); - write(dynabuf, "."); - write(dynabuf, msg.version % 10); - write(dynabuf, " "); + BOOST_ASSERT(msg.version == 10 || msg.version == 11); + switch(msg.version) + { + case 10: + write(dynabuf, "HTTP/1.0 "); + break; + case 11: + write(dynabuf, "HTTP/1.1 "); + break; + } write(dynabuf, msg.status); write(dynabuf, " "); write(dynabuf, msg.reason); @@ -80,13 +91,169 @@ write_fields(DynamicBuffer& dynabuf, FieldSequence const& fields) } } -template +} // detail + +//------------------------------------------------------------------------------ + +namespace detail { + +template +class write_streambuf_op +{ + struct data + { + bool cont; + Stream& s; + streambuf sb; + int state = 0; + + data(Handler& handler, Stream& s_, + streambuf&& sb_) + : cont(beast_asio_helpers:: + is_continuation(handler)) + , s(s_) + , sb(std::move(sb_)) + { + } + }; + + handler_ptr d_; + +public: + write_streambuf_op(write_streambuf_op&&) = default; + write_streambuf_op(write_streambuf_op const&) = default; + + template + write_streambuf_op(DeducedHandler&& h, Stream& s, + Args&&... args) + : d_(make_handler_ptr( + std::forward(h), + s, std::forward(args)...)) + { + (*this)(error_code{}, 0, false); + } + + void + operator()(error_code ec, + std::size_t bytes_transferred, bool again = true); + + friend + void* asio_handler_allocate( + std::size_t size, write_streambuf_op* op) + { + return beast_asio_helpers:: + allocate(size, op->d_.handler()); + } + + friend + void asio_handler_deallocate( + void* p, std::size_t size, write_streambuf_op* op) + { + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); + } + + friend + bool asio_handler_is_continuation(write_streambuf_op* op) + { + return op->d_->cont; + } + + template + friend + void asio_handler_invoke(Function&& f, write_streambuf_op* op) + { + return beast_asio_helpers:: + invoke(f, op->d_.handler()); + } +}; + +template +void +write_streambuf_op:: +operator()(error_code ec, std::size_t, bool again) +{ + auto& d = *d_; + d.cont = d.cont || again; + while(! ec && d.state != 99) + { + switch(d.state) + { + case 0: + { + d.state = 99; + boost::asio::async_write(d.s, + d.sb.data(), std::move(*this)); + return; + } + } + } + d_.invoke(ec); +} + +} // detail + +template +void +write(SyncWriteStream& stream, + header const& msg) +{ + static_assert(is_SyncWriteStream::value, + "SyncWriteStream requirements not met"); + error_code ec; + write(stream, msg, ec); + if(ec) + throw system_error{ec}; +} + +template +void +write(SyncWriteStream& stream, + header const& msg, + error_code& ec) +{ + static_assert(is_SyncWriteStream::value, + "SyncWriteStream requirements not met"); + streambuf sb; + detail::write_start_line(sb, msg); + detail::write_fields(sb, msg.fields); + beast::write(sb, "\r\n"); + boost::asio::write(stream, sb.data(), ec); +} + +template +typename async_completion< + WriteHandler, void(error_code)>::result_type +async_write(AsyncWriteStream& stream, + header const& msg, + WriteHandler&& handler) +{ + static_assert(is_AsyncWriteStream::value, + "AsyncWriteStream requirements not met"); + beast::async_completion completion(handler); + streambuf sb; + detail::write_start_line(sb, msg); + detail::write_fields(sb, msg.fields); + beast::write(sb, "\r\n"); + detail::write_streambuf_op{ + completion.handler, stream, std::move(sb)}; + return completion.result.get(); +} + +//------------------------------------------------------------------------------ + +namespace detail { + +template struct write_preparation { - using headers_type = - basic_headers>; - - message_v1 const& msg; + message const& msg; typename Body::writer w; streambuf sb; bool chunked; @@ -94,14 +261,14 @@ struct write_preparation explicit write_preparation( - message_v1 const& msg_) + message const& msg_) : msg(msg_) , w(msg) , chunked(token_list{ - msg.headers["Transfer-Encoding"]}.exists("chunked")) + msg.fields["Transfer-Encoding"]}.exists("chunked")) , close(token_list{ - msg.headers["Connection"]}.exists("close") || - (msg.version < 11 && ! msg.headers.exists( + msg.fields["Connection"]}.exists("close") || + (msg.version < 11 && ! msg.fields.exists( "Content-Length"))) { } @@ -112,39 +279,34 @@ struct write_preparation w.init(ec); if(ec) return; - write_firstline(sb, msg); - write_fields(sb, msg.headers); + + write_start_line(sb, msg); + write_fields(sb, msg.fields); beast::write(sb, "\r\n"); } }; template + bool isRequest, class Body, class Fields> class write_op { - using alloc_type = - handler_alloc; - struct data { + bool cont; Stream& s; // VFALCO How do we use handler_alloc in write_preparation? write_preparation< - isRequest, Body, Headers> wp; - Handler h; + isRequest, Body, Fields> wp; resume_context resume; resume_context copy; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, Stream& s_, - message_v1 const& m_) - : s(s_) + data(Handler& handler, Stream& s_, + message const& m_) + : cont(beast_asio_helpers:: + is_continuation(handler)) + , s(s_) , wp(m_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; @@ -161,14 +323,14 @@ class write_op } template - void operator()(ConstBufferSequence const& buffers) + void operator()(ConstBufferSequence const& buffers) const { auto& d = *self_.d_; - // write headers and body + // write header and body if(d.wp.chunked) boost::asio::async_write(d.s, buffer_cat(d.wp.sb.data(), - detail::chunk_encode(buffers)), + chunk_encode(false, buffers)), std::move(self_)); else boost::asio::async_write(d.s, @@ -189,13 +351,13 @@ class write_op } template - void operator()(ConstBufferSequence const& buffers) + void operator()(ConstBufferSequence const& buffers) const { auto& d = *self_.d_; // write body if(d.wp.chunked) boost::asio::async_write(d.s, - detail::chunk_encode(buffers), + chunk_encode(false, buffers), std::move(self_)); else boost::asio::async_write(d.s, @@ -203,7 +365,7 @@ class write_op } }; - std::shared_ptr d_; + handler_ptr d_; public: write_op(write_op&&) = default; @@ -211,7 +373,7 @@ public: template write_op(DeducedHandler&& h, Stream& s, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), s, std::forward(args)...)) { @@ -220,7 +382,7 @@ public: d.resume = { [sp]() mutable { - write_op self(std::move(sp)); + write_op self{std::move(sp)}; self.d_->cont = false; auto& ios = self.d_->s.get_io_service(); ios.dispatch(bind_handler(std::move(self), @@ -231,7 +393,7 @@ public: } explicit - write_op(std::shared_ptr d) + write_op(handler_ptr d) : d_(std::move(d)) { } @@ -244,16 +406,16 @@ public: void* asio_handler_allocate( std::size_t size, write_op* op) { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + return beast_asio_helpers:: + allocate(size, op->d_.handler()); } friend void asio_handler_deallocate( void* p, std::size_t size, write_op* op) { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); } friend @@ -266,15 +428,15 @@ public: friend void asio_handler_invoke(Function&& f, write_op* op) { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + return beast_asio_helpers:: + invoke(f, op->d_.handler()); } }; template + bool isRequest, class Body, class Fields> void -write_op:: +write_op:: operator()(error_code ec, std::size_t, bool again) { auto& d = *d_; @@ -300,7 +462,7 @@ operator()(error_code ec, std::size_t, bool again) case 1: { - auto const result = d.wp.w( + boost::tribool const result = d.wp.w.write( std::move(d.copy), ec, writef0_lambda{*this}); if(ec) { @@ -323,7 +485,7 @@ operator()(error_code ec, std::size_t, bool again) return; } - // sent headers and body + // sent header and body case 2: d.wp.sb.consume(d.wp.sb.size()); d.state = 3; @@ -331,7 +493,7 @@ operator()(error_code ec, std::size_t, bool again) case 3: { - auto const result = d.wp.w( + boost::tribool result = d.wp.w.write( std::move(d.copy), ec, writef_lambda{*this}); if(ec) { @@ -360,7 +522,7 @@ operator()(error_code ec, std::size_t, bool again) // write final chunk d.state = 5; boost::asio::async_write(d.s, - detail::chunk_encode_final(), std::move(*this)); + chunk_encode_final(), std::move(*this)); return; case 5: @@ -373,9 +535,9 @@ operator()(error_code ec, std::size_t, bool again) break; } } - d.h(ec); - d.resume = {}; d.copy = {}; + d.resume = {}; + d_.invoke(ec); } template @@ -397,12 +559,12 @@ public: } template - void operator()(ConstBufferSequence const& buffers) + void operator()(ConstBufferSequence const& buffers) const { - // write headers and body + // write header and body if(chunked_) boost::asio::write(stream_, buffer_cat( - sb_.data(), detail::chunk_encode(buffers)), ec_); + sb_.data(), chunk_encode(false, buffers)), ec_); else boost::asio::write(stream_, buffer_cat( sb_.data(), buffers), ec_); @@ -426,12 +588,12 @@ public: } template - void operator()(ConstBufferSequence const& buffers) + void operator()(ConstBufferSequence const& buffers) const { // write body if(chunked_) boost::asio::write(stream_, - detail::chunk_encode(buffers), ec_); + chunk_encode(false, buffers), ec_); else boost::asio::write(stream_, buffers, ec_); } @@ -439,18 +601,21 @@ public: } // detail -//------------------------------------------------------------------------------ - template + bool isRequest, class Body, class Fields> void write(SyncWriteStream& stream, - message_v1 const& msg) + message const& msg) { static_assert(is_SyncWriteStream::value, "SyncWriteStream requirements not met"); - static_assert(is_WritableBody::value, - "WritableBody requirements not met"); + static_assert(is_Body::value, + "Body requirements not met"); + static_assert(has_writer::value, + "Body has no writer"); + static_assert(is_Writer>::value, + "Writer requirements not met"); error_code ec; write(stream, msg, ec); if(ec) @@ -458,17 +623,22 @@ write(SyncWriteStream& stream, } template + bool isRequest, class Body, class Fields> void write(SyncWriteStream& stream, - message_v1 const& msg, - boost::system::error_code& ec) + message const& msg, + error_code& ec) { static_assert(is_SyncWriteStream::value, "SyncWriteStream requirements not met"); - static_assert(is_WritableBody::value, - "WritableBody requirements not met"); - detail::write_preparation wp(msg); + static_assert(is_Body::value, + "Body requirements not met"); + static_assert(has_writer::value, + "Body has no writer"); + static_assert(is_Writer>::value, + "Writer requirements not met"); + detail::write_preparation wp(msg); wp.init(ec); if(ec) return; @@ -483,9 +653,11 @@ write(SyncWriteStream& stream, cv.notify_one(); }}; auto copy = resume; - boost::tribool result = wp.w(std::move(copy), - ec, detail::writef0_lambda{stream, wp.sb, wp.chunked, ec}); + boost::tribool result = + wp.w.write(std::move(copy), ec, + detail::writef0_lambda{stream, + wp.sb, wp.chunked, ec}); if(ec) return; if(boost::indeterminate(result)) @@ -504,11 +676,11 @@ write(SyncWriteStream& stream, wp.sb.consume(wp.sb.size()); if(! result) { + detail::writef_lambda wf{ + stream, wp.chunked, ec}; for(;;) { - result = wp.w(std::move(copy), ec, - detail::writef_lambda{ - stream, wp.chunked, ec}); + result = wp.w.write(std::move(copy), ec, wf); if(ec) return; if(result) @@ -528,7 +700,7 @@ write(SyncWriteStream& stream, // final body chunk with the final chunk delimiter. // // write final chunk - boost::asio::write(stream, detail::chunk_encode_final(), ec); + boost::asio::write(stream, chunk_encode_final(), ec); if(ec) return; } @@ -540,82 +712,58 @@ write(SyncWriteStream& stream, } template typename async_completion< WriteHandler, void(error_code)>::result_type async_write(AsyncWriteStream& stream, - message_v1 const& msg, + message const& msg, WriteHandler&& handler) { static_assert(is_AsyncWriteStream::value, "AsyncWriteStream requirements not met"); - static_assert(is_WritableBody::value, - "WritableBody requirements not met"); + static_assert(is_Body::value, + "Body requirements not met"); + static_assert(has_writer::value, + "Body has no writer"); + static_assert(is_Writer>::value, + "Writer requirements not met"); beast::async_completion completion(handler); detail::write_op{completion.handler, stream, msg}; + isRequest, Body, Fields>{completion.handler, stream, msg}; return completion.result.get(); } -namespace detail { +//------------------------------------------------------------------------------ -class ostream_SyncStream -{ - std::ostream& os_; - -public: - ostream_SyncStream(std::ostream& os) - : os_(os) - { - } - - template - std::size_t - write_some(ConstBufferSequence const& buffers) - { - error_code ec; - auto const n = write_some(buffers, ec); - if(ec) - throw system_error{ec}; - return n; - } - - template - std::size_t - write_some(ConstBufferSequence const& buffers, - error_code& ec) - { - std::size_t n = 0; - using boost::asio::buffer_cast; - using boost::asio::buffer_size; - for(auto const& buffer : buffers) - { - os_.write(buffer_cast(buffer), - buffer_size(buffer)); - if(os_.fail()) - { - ec = boost::system::errc::make_error_code( - boost::system::errc::no_stream_resources); - break; - } - n += buffer_size(buffer); - } - return n; - } -}; - -} // detail - -template +template std::ostream& operator<<(std::ostream& os, - message_v1 const& msg) + header const& msg) { - static_assert(is_WritableBody::value, - "WritableBody requirements not met"); - detail::ostream_SyncStream oss(os); + beast::detail::sync_ostream oss{os}; + error_code ec; + write(oss, msg, ec); + if(ec) + throw system_error{ec}; + return os; +} + +template +std::ostream& +operator<<(std::ostream& os, + message const& msg) +{ + static_assert(is_Body::value, + "Body requirements not met"); + static_assert(has_writer::value, + "Body has no writer"); + static_assert(is_Writer>::value, + "Writer requirements not met"); + beast::detail::sync_ostream oss{os}; error_code ec; write(oss, msg, ec); if(ec && ec != boost::asio::error::eof) diff --git a/include/beast/http/message.hpp b/include/beast/http/message.hpp index 6c1a57c93..ebe172384 100644 --- a/include/beast/http/message.hpp +++ b/include/beast/http/message.hpp @@ -8,7 +8,7 @@ #ifndef BEAST_HTTP_MESSAGE_HPP #define BEAST_HTTP_MESSAGE_HPP -#include +#include #include #include #include @@ -18,87 +18,273 @@ namespace beast { namespace http { -namespace detail { +#if GENERATING_DOCS +/** A container for a HTTP request or response header. -struct request_fields + A header includes the Start Line and Fields. + + Some use-cases: + + @li When the message has no body, such as a response to a HEAD request. + + @li When the caller wishes to defer instantiation of the body. + + @li Invoke algorithms which operate on the header only. +*/ +template +struct header + +#else +template +struct header; + +template +struct header +#endif { + /// Indicates if the header is a request or response. +#if GENERATING_DOCS + static bool constexpr is_request = isRequest; + +#else + static bool constexpr is_request = true; +#endif + + /// The type representing the fields. + using fields_type = Fields; + + /** The HTTP version. + + This holds both the major and minor version numbers, + using these formulas: + @code + major = version / 10; + minor = version % 10; + @endcode + */ + int version; + + /** The Request Method + + @note This field is present only if `isRequest == true`. + */ std::string method; + + /** The Request URI + + @note This field is present only if `isRequest == true`. + */ std::string url; -protected: - void - swap(request_fields& other) + /// The HTTP field values. + fields_type fields; + + /// Default constructor + header() = default; + + /// Move constructor + header(header&&) = default; + + /// Copy constructor + header(header const&) = default; + + /// Move assignment + header& operator=(header&&) = default; + + /// Copy assignment + header& operator=(header const&) = default; + + /** Construct the header. + + All arguments are forwarded to the constructor + of the `fields` member. + + @note This constructor participates in overload resolution + if and only if the first parameter is not convertible to + `header`. + */ +#if GENERATING_DOCS + template + explicit + header(Args&&... args); + +#else + template 0) || ! std::is_convertible< + typename std::decay::type, + header>::value>::type> + explicit + header(Arg1&& arg1, ArgN&&... argn) + : fields(std::forward(arg1), + std::forward(argn)...) { - using std::swap; - swap(method, other.method); - swap(url, other.url); } }; -struct response_fields +/** A container for a HTTP request or response header. + + A header includes the Start Line and Fields. + + Some use-cases: + + @li When the message has no body, such as a response to a HEAD request. + + @li When the caller wishes to defer instantiation of the body. + + @li Invoke algorithms which operate on the header only. +*/ +template +struct header { - int status; - std::string reason; + /// Indicates if the header is a request or response. + static bool constexpr is_request = false; -protected: - void - swap(response_fields& other) + /// The type representing the fields. + using fields_type = Fields; + + /** The HTTP version. + + This holds both the major and minor version numbers, + using these formulas: + @code + major = version / 10; + minor = version % 10; + @endcode + */ + int version; + + /// The HTTP field values. + fields_type fields; + + /// Default constructor + header() = default; + + /// Move constructor + header(header&&) = default; + + /// Copy constructor + header(header const&) = default; + + /// Move assignment + header& operator=(header&&) = default; + + /// Copy assignment + header& operator=(header const&) = default; + + /** Construct the header. + + All arguments are forwarded to the constructor + of the `fields` member. + + @note This constructor participates in overload resolution + if and only if the first parameter is not convertible to + `header`. + */ + template 0) || ! std::is_convertible< + typename std::decay::type, + header>::value>::type> + explicit + header(Arg1&& arg1, ArgN&&... argn) + : fields(std::forward(arg1), + std::forward(argn)...) { - using std::swap; - swap(status, other.status); - swap(reason, other.reason); } +#endif + + /** The Response Status-Code. + + @note This field is present only if `isRequest == false`. + */ + int status; + + /** The Response Reason-Phrase. + + The Reason-Phrase is obsolete as of rfc7230. + + @note This field is present only if `isRequest == false`. + */ + std::string reason; }; -} // detail +/** A container for a complete HTTP message. -/** A HTTP message. - - A message can be a request or response, depending on the `isRequest` - template argument value. Requests and responses have different types, - so functions may be overloaded on them if desired. + A message can be a request or response, depending on the + `isRequest` template argument value. Requests and responses + have different types; functions may be overloaded based on + the type if desired. The `Body` template argument type determines the model used to read or write the content body of the message. - @tparam isRequest `true` if this is a request. + @tparam isRequest `true` if this represents a request, + or `false` if this represents a response. Some class data + members are conditionally present depending on this value. @tparam Body A type meeting the requirements of Body. - @tparam Headers A type meeting the requirements of Headers. + @tparam Fields The type of container used to hold the + field value pairs. */ -template -struct message - : std::conditional::type +template +struct message : header { - /** The type controlling the body traits. + /// The base class used to hold the header portion of the message. + using base_type = header; - The body member will be of type `body_type::value_type`. + /** The type providing the body traits. + + The @ref message::body member will be of type `body_type::value_type`. */ using body_type = Body; - /// The type representing the headers. - using headers_type = Headers; - - /// Indicates if the message is a request. - using is_request = - std::integral_constant; - - /// The container holding the headers. - headers_type headers; - - /// A container representing the body. + /// A value representing the body. typename Body::value_type body; /// Default constructor message() = default; + /** Construct a message from a header. + + Additional arguments, if any, are forwarded to + the constructor of the body member. + */ + template + explicit + message(base_type&& base, Args&&... args) + : base_type(std::move(base)) + , body(std::forward(args)...) + { + } + + /** Construct a message from a header. + + Additional arguments, if any, are forwarded to + the constructor of the body member. + */ + template + explicit + message(base_type const& base, Args&&... args) + : base_type(base) + , body(std::forward(args)...) + { + } + /** Construct a message. @param u An argument forwarded to the body constructor. + + @note This constructor participates in overload resolution + only if `u` is not convertible to `base_type`. */ - template + template::type, base_type>::value> +#endif + > explicit message(U&& u) : body(std::forward(u)) @@ -108,11 +294,20 @@ struct message /** Construct a message. @param u An argument forwarded to the body constructor. - @param v An argument forwarded to the headers constructor. + + @param v An argument forwarded to the fields constructor. + + @note This constructor participates in overload resolution + only if `u` is not convertible to `base_type`. */ - template + template::type, base_type>::value> +#endif + > message(U&& u, V&& v) - : headers(std::forward(v)) + : base_type(std::forward(v)) , body(std::forward(u)) { } @@ -126,13 +321,13 @@ struct message : message(std::piecewise_construct, un, beast::detail::make_index_sequence{}) { - } /** Construct a message. @param un A tuple forwarded as a parameter pack to the body constructor. - @param vn A tuple forwarded as a parameter pack to the headers constructor. + + @param vn A tuple forwarded as a parameter pack to the fields constructor. */ template message(std::piecewise_construct_t, @@ -143,14 +338,21 @@ struct message { } - /// Swap this message for another message. - void - swap(message& other); + /// Returns the header portion of the message + base_type& + base() + { + return *this; + } + + /// Returns the header portion of the message + base_type const& + base() const + { + return *this; + } private: - using base = typename std::conditional::type; - template message(std::piecewise_construct_t, std::tuple& tu, beast::detail::index_sequence) @@ -164,44 +366,106 @@ private: std::tuple& tu, std::tuple& tv, beast::detail::index_sequence, beast::detail::index_sequence) - : headers(std::forward(std::get(tv))...) + : base_type(std::forward(std::get(tv))...) , body(std::forward(std::get(tu))...) { } }; -template -void -message:: -swap(message& other) -{ - using std::swap; - base::swap(other); - swap(headers, other.headers); - swap(body, other.body); -} +//------------------------------------------------------------------------------ -/// Swap one message for another message. -template -inline +#if GENERATING_DOCS +/** Swap two header objects. + + @par Requirements + `Fields` is @b Swappable. +*/ +template void -swap(message& lhs, - message& rhs) -{ - lhs.swap(rhs); -} +swap( + header& m1, + header& m2); +#endif + +/** Swap two message objects. + + @par Requirements: + `Body::value_type` and `Fields` are @b Swappable. +*/ +template +void +swap( + message& m1, + message& m2); + +/// A typical HTTP request header +using request_header = header; + +/// Typical HTTP response header +using response_header = header; /// A typical HTTP request -template>> -using request = message; +template +using request = message; /// A typical HTTP response -template>> -using response = message; +template +using response = message; + +//------------------------------------------------------------------------------ + +/** Returns `true` if the HTTP/1 message indicates a keep alive. + + Undefined behavior if version is greater than 11. +*/ +template +bool +is_keep_alive(header const& msg); + +/** Returns `true` if the HTTP/1 message indicates an Upgrade request or response. + + Undefined behavior if version is greater than 11. +*/ +template +bool +is_upgrade(header const& msg); + +/** HTTP/1 connection prepare options. + + @note These values are used with @ref prepare. +*/ +enum class connection +{ + /// Specify Connection: close. + close, + + /// Specify Connection: keep-alive where possible. + keep_alive, + + /// Specify Connection: upgrade. + upgrade +}; + +/** Prepare a HTTP message. + + This function will adjust the Content-Length, Transfer-Encoding, + and Connection fields of the message based on the properties of + the body and the options passed in. + + @param msg The message to prepare. The fields may be modified. + + @param options A list of prepare options. +*/ +template< + bool isRequest, class Body, class Fields, + class... Options> +void +prepare(message& msg, + Options&&... options); } // http } // beast +#include + #endif diff --git a/include/beast/http/message_v1.hpp b/include/beast/http/message_v1.hpp deleted file mode 100644 index 68abc68c1..000000000 --- a/include/beast/http/message_v1.hpp +++ /dev/null @@ -1,135 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_HTTP_MESSAGE_V1_HPP -#define BEAST_HTTP_MESSAGE_V1_HPP - -#include -#include -#include - -namespace beast { -namespace http { - -/** A HTTP/1 message. - - A message can be a request or response, depending on the `isRequest` - template argument value. Requests and responses have different types, - so functions may be overloaded on them if desired. - - The `Body` template argument type determines the model used - to read or write the content body of the message. - - @tparam isRequest `true` if this is a request. - - @tparam Body A type meeting the requirements of Body. - - @tparam Headers A type meeting the requirements of Headers. -*/ -template -struct message_v1 : message -{ - /// HTTP/1 version (10 or 11) - int version; - - /// Default constructor - message_v1() = default; - - /// Constructor - template - explicit - message_v1(Arg1& arg1, Argn&&... argn) - : message( - std::forward(arg1), - std::forward(argn)...) - { - } - - /// Swap this message for another message. - void - swap(message_v1& other); -}; - -template -void -message_v1:: -swap(message_v1& other) -{ - using std::swap; - message::swap(other); - swap(version, other.version); -} - -/// Swap one message for another message. -template -inline -void -swap(message_v1& lhs, - message_v1& rhs) -{ - lhs.swap(rhs); -} - -/// A typical HTTP/1 request -template>> -using request_v1 = message_v1; - -/// A typical HTTP/1 response -template>> -using response_v1 = message_v1; - -/// Returns `true` if a HTTP/1 message indicates a keep alive -template -bool -is_keep_alive(message_v1 const& msg); - -/// Returns `true` if a HTTP/1 message indicates an Upgrade request or response -template -bool -is_upgrade(message_v1 const& msg); - -/** HTTP/1 connection prepare options. - - @note These values are used with @ref prepare. -*/ -enum class connection -{ - /// Specify Connection: close. - close, - - /// Specify Connection: keep-alive where possible. - keep_alive, - - /// Specify Connection: upgrade. - upgrade -}; - -/** Prepare a HTTP/1 message. - - This function will adjust the Content-Length, Transfer-Encoding, - and Connection headers of the message based on the properties of - the body and the options passed in. - - @param msg The message to prepare. The headers may be modified. - - @param options A list of prepare options. -*/ -template< - bool isRequest, class Body, class Headers, - class... Options> -void -prepare(message_v1& msg, - Options&&... options); - -} // http -} // beast - -#include - -#endif diff --git a/include/beast/http/parse.hpp b/include/beast/http/parse.hpp new file mode 100644 index 000000000..ed7f4f44d --- /dev/null +++ b/include/beast/http/parse.hpp @@ -0,0 +1,154 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_HTTP_PARSE_HPP +#define BEAST_HTTP_PARSE_HPP + +#include +#include + +namespace beast { +namespace http { + +/** Parse an object from a stream. + + This function synchronously reads from a stream and passes + data to the specified parser. The call will block until one + of the following conditions are met: + + @li The parser indicates that parsing is complete. + + @li An error occurs in the stream or parser. + + This function is implemented in terms of one or more calls + to the stream's `read_some` function. The implementation may + read additional octets that lie past the end of the object + being parsed. This additional data is stored in the stream + buffer, which may be used in subsequent calls. + + @note This algorithm is generic, and not specific to HTTP + messages. It is up to the parser to determine what predicate + defines a complete operation. + + @param stream The stream from which the data is to be read. + The type must support the @b SyncReadStream concept. + + @param dynabuf A @b DynamicBuffer holding additional bytes + read by the implementation from the stream. This is both + an input and an output parameter; on entry, any data in the + stream buffer's input sequence will be given to the parser + first. + + @param parser An object meeting the requirements of @b Parser + which will receive the data. + + @throws system_error Thrown on failure. +*/ +template +void +parse(SyncReadStream& stream, + DynamicBuffer& dynabuf, Parser& parser); + +/** Parse an object from a stream. + + This function synchronously reads from a stream and passes + data to the specified parser. The call will block until one + of the following conditions are met: + + @li The parser indicates that parsing is complete. + + @li An error occurs in the stream or parser. + + This function is implemented in terms of one or more calls + to the stream's `read_some` function. The implementation may + read additional octets that lie past the end of the object + being parsed. This additional data is stored in the stream + buffer, which may be used in subsequent calls. + + @note This algorithm is generic, and not specific to HTTP + messages. It is up to the parser to determine what predicate + defines a complete operation. + + @param stream The stream from which the data is to be read. + The type must support the @b SyncReadStream concept. + + @param dynabuf A @b DynamicBuffer holding additional bytes + read by the implementation from the stream. This is both + an input and an output parameter; on entry, any data in the + stream buffer's input sequence will be given to the parser + first. + + @param parser An object meeting the requirements of @b Parser + which will receive the data. + + @param ec Set to the error, if any occurred. +*/ +template +void +parse(SyncReadStream& stream, + DynamicBuffer& dynabuf, Parser& parser, error_code& ec); + +/** Start an asynchronous operation to parse an object from a stream. + + This function is used to asynchronously read from a stream and + pass the data to the specified parser. The function call always + returns immediately. The asynchronous operation will continue + until one of the following conditions is true: + + @li The parser indicates that parsing is complete. + + @li An error occurs in the stream or parser. + + This operation is implemented in terms of one or more calls to + the next layer's `async_read_some` function, and is known as a + composed operation. The program must ensure that the + stream performs no other operations until this operation completes. + The implementation may read additional octets that lie past the + end of the object being parsed. This additional data is stored + in the stream buffer, which may be used in subsequent calls. + + @param stream The stream from which the data is to be read. + The type must support the @b AsyncReadStream concept. + + @param dynabuf A @b DynamicBuffer holding additional bytes + read by the implementation from the stream. This is both + an input and an output parameter; on entry, any data in the + stream buffer's input sequence will be given to the parser + first. + + @param parser An object meeting the requirements of @b Parser + which will receive the data. This object must remain valid + until the completion handler is invoked. + + @param handler The handler to be called when the request + completes. Copies will be made of the handler as required. + The equivalent function signature of the handler must be: + @code void handler( + error_code const& error // result of operation + ); @endcode + Regardless of whether the asynchronous operation completes + immediately or not, the handler will not be invoked from within + this function. Invocation of the handler will be performed in a + manner equivalent to using `boost::asio::io_service::post`. +*/ +template +#if GENERATING_DOCS +void_or_deduced +#else +typename async_completion< + ReadHandler, void(error_code)>::result_type +#endif +async_parse(AsyncReadStream& stream, DynamicBuffer& dynabuf, + Parser& parser, ReadHandler&& handler); + +} // http +} // beast + +#include + +#endif diff --git a/include/beast/http/parse_error.hpp b/include/beast/http/parse_error.hpp index b4d5c8d04..43a664683 100644 --- a/include/beast/http/parse_error.hpp +++ b/include/beast/http/parse_error.hpp @@ -15,15 +15,12 @@ namespace http { enum class parse_error { - success = 0, - - connection_closed, + connection_closed = 1, bad_method, bad_uri, bad_version, bad_crlf, - bad_request, bad_status, bad_reason, @@ -32,145 +29,19 @@ enum class parse_error bad_value, bad_content_length, illegal_content_length, - bad_on_headers_rv, invalid_chunk_size, invalid_ext_name, invalid_ext_val, - headers_too_big, + header_too_big, body_too_big, - short_read, - - general + short_read }; -class parse_error_category : public boost::system::error_category -{ -public: - const char* - name() const noexcept override - { - return "http"; - } - - std::string - message(int ev) const override - { - switch(static_cast(ev)) - { - case parse_error::connection_closed: - return "data after Connection close"; - - case parse_error::bad_method: - return "bad method"; - - case parse_error::bad_uri: - return "bad request-target"; - - case parse_error::bad_version: - return "bad HTTP-Version"; - - case parse_error::bad_crlf: - return "missing CRLF"; - - case parse_error::bad_request: - return "bad reason-phrase"; - - case parse_error::bad_status: - return "bad status-code"; - - case parse_error::bad_reason: - return "bad reason-phrase"; - - case parse_error::bad_field: - return "bad field token"; - - case parse_error::bad_value: - return "bad field-value"; - - case parse_error::bad_content_length: - return "bad Content-Length"; - - case parse_error::illegal_content_length: - return "illegal Content-Length with chunked Transfer-Encoding"; - - case parse_error::bad_on_headers_rv: - return "on_headers returned an unknown value"; - - case parse_error::invalid_chunk_size: - return "invalid chunk size"; - - case parse_error::invalid_ext_name: - return "invalid ext name"; - - case parse_error::invalid_ext_val: - return "invalid ext val"; - - case parse_error::headers_too_big: - return "headers size limit exceeded"; - - case parse_error::body_too_big: - return "body size limit exceeded"; - - case parse_error::short_read: - return "unexpected end of data"; - - default: - return "parse error"; - } - } - - boost::system::error_condition - default_error_condition(int ev) const noexcept override - { - return boost::system::error_condition(ev, *this); - } - - bool - equivalent(int ev, - boost::system::error_condition const& condition - ) const noexcept override - { - return condition.value() == ev && - &condition.category() == this; - } - - bool - equivalent(error_code const& error, int ev) const noexcept override - { - return error.value() == ev && - &error.category() == this; - } -}; - -inline -boost::system::error_category const& -get_parse_error_category() -{ - static parse_error_category const cat{}; - return cat; -} - -inline -boost::system::error_code -make_error_code(parse_error ev) -{ - return error_code(static_cast(ev), - get_parse_error_category()); -} - } // http } // beast -namespace boost { -namespace system { -template<> -struct is_error_code_enum -{ - static bool const value = true; -}; -} // system -} // boost +#include #endif diff --git a/include/beast/http/parser_v1.hpp b/include/beast/http/parser_v1.hpp index aada5243b..fbcd34018 100644 --- a/include/beast/http/parser_v1.hpp +++ b/include/beast/http/parser_v1.hpp @@ -8,10 +8,13 @@ #ifndef BEAST_HTTP_PARSER_V1_HPP #define BEAST_HTTP_PARSER_V1_HPP -#include #include -#include +#include +#include #include +#include +#include +#include #include #include #include @@ -20,21 +23,6 @@ namespace beast { namespace http { -namespace detail { - -struct parser_request -{ - std::string method_; - std::string uri_; -}; - -struct parser_response -{ - std::string reason_; -}; - -} // detail - /** Skip body option. The options controls whether or not the parser expects to see a @@ -45,15 +33,15 @@ struct parser_response For example, a 200 response to a CONNECT request from a tunneling proxy. In these cases, callers use the @ref skip_body option to inform the parser that no body is expected. The parser will consider - the message complete after the all headers have been received. + the message complete after the header has been received. Example: @code - parser_v1 p; + parser_v1 p; p.set_option(skip_body{true}); @endcode - @note Objects of this type are passed to @ref basic_parser_v1::set_option. + @note Objects of this type are passed to @ref parser_v1::set_option. */ struct skip_body { @@ -69,51 +57,102 @@ struct skip_body /** A parser for producing HTTP/1 messages. This class uses the basic HTTP/1 wire format parser to convert - a series of octets into a `message_v1`. + a series of octets into a `message`. @note A new instance of the parser is required for each message. */ -template +template class parser_v1 : public basic_parser_v1> + parser_v1> , private std::conditional::type + detail::request_parser_base, + detail::response_parser_base>::type { public: /// The type of message this parser produces. using message_type = - message_v1; + message; private: - static_assert(is_ReadableBody::value, - "ReadableBody requirements not met"); + using reader = + typename message_type::body_type::reader; + + static_assert(is_Body::value, + "Body requirements not met"); + static_assert(has_reader::value, + "Body has no reader"); + static_assert(is_Reader::value, + "Reader requirements not met"); std::string field_; std::string value_; message_type m_; - typename message_type::body_type::reader r_; + boost::optional r_; std::uint8_t skip_body_ = 0; + bool flush_ = false; public: + /// Default constructor + parser_v1() = default; + + /// Move constructor parser_v1(parser_v1&&) = default; + + /// Copy constructor (disallowed) parser_v1(parser_v1 const&) = delete; + + /// Move assignment (disallowed) parser_v1& operator=(parser_v1&&) = delete; + + /// Copy assignment (disallowed) parser_v1& operator=(parser_v1 const&) = delete; /** Construct the parser. - @param args A list of arguments forwarded to the message constructor. + @param args Forwarded to the message constructor. + + @note This function participates in overload resolution only + if the first argument is not a parser or fields parser. + */ +#if GENERATING_DOCS + template + explicit + parser_v1(Args&&... args); +#else + template::type, + header_parser_v1>::value && + ! std::is_same::type, parser_v1>::value + >::type> + explicit + parser_v1(Arg1&& arg1, ArgN&&... argn) + : m_(std::forward(arg1), + std::forward(argn)...) + { + } +#endif + + /** Construct the parser from a fields parser. + + @param parser The fields parser to construct from. + @param args Forwarded to the message body constructor. */ template explicit - parser_v1(Args&&... args) - : m_(std::forward(args)...) - , r_(m_) + parser_v1(header_parser_v1& parser, + Args&&... args) + : m_(parser.release(), std::forward(args)...) { + static_cast>&>(*this) = parser; } - /// Set the expect body option. + /// Set the skip body option. void set_option(skip_body const& o) { @@ -122,7 +161,7 @@ public: /** Returns the parsed message. - Only valid if `complete()` would return `true`. + Only valid if @ref complete would return `true`. */ message_type const& get() const @@ -132,7 +171,7 @@ public: /** Returns the parsed message. - Only valid if `complete()` would return `true`. + Only valid if @ref complete would return `true`. */ message_type& get() @@ -140,13 +179,13 @@ public: return m_; } - /** Returns the parsed message. + /** Returns ownership of the parsed message. - Ownership is transferred to the caller. - Only valid if `complete()` would return `true`. + Ownership is transferred to the caller. Only + valid if @ref complete would return `true`. Requires: - `message` is MoveConstructible + `message` is @b MoveConstructible */ message_type release() @@ -161,12 +200,13 @@ private: void flush() { - if(! value_.empty()) - { - m_.headers.insert(field_, value_); - field_.clear(); - value_.clear(); - } + if(! flush_) + return; + flush_ = false; + BOOST_ASSERT(! field_.empty()); + m_.fields.insert(field_, value_); + field_.clear(); + value_.clear(); } void on_start(error_code&) @@ -188,6 +228,30 @@ private: this->reason_.append(s.data(), s.size()); } + void on_request_or_response(std::true_type) + { + m_.method = std::move(this->method_); + m_.url = std::move(this->uri_); + } + + void on_request_or_response(std::false_type) + { + m_.status = this->status_code(); + m_.reason = std::move(this->reason_); + } + + void on_request(error_code&) + { + on_request_or_response( + std::integral_constant{}); + } + + void on_response(error_code&) + { + on_request_or_response( + std::integral_constant{}); + } + void on_field(boost::string_ref const& s, error_code&) { flush(); @@ -197,42 +261,29 @@ private: void on_value(boost::string_ref const& s, error_code&) { value_.append(s.data(), s.size()); + flush_ = true; } - void set(std::true_type) - { - m_.method = std::move(this->method_); - m_.url = std::move(this->uri_); - } - - void set(std::false_type) - { - m_.status = this->status_code(); - m_.reason = std::move(this->reason_); - } - - int on_headers(std::uint64_t, error_code&) + void + on_header(std::uint64_t, error_code&) { flush(); m_.version = 10 * this->http_major() + this->http_minor(); - return skip_body_; } - void on_request(error_code& ec) + body_what + on_body_what(std::uint64_t, error_code& ec) { - set(std::integral_constant< - bool, isRequest>{}); - } - - void on_response(error_code& ec) - { - set(std::integral_constant< - bool, isRequest>{}); + if(skip_body_) + return body_what::skip; + r_.emplace(m_); + r_->init(ec); + return body_what::normal; } void on_body(boost::string_ref const& s, error_code& ec) { - r_.write(s.data(), s.size(), ec); + r_->write(s.data(), s.size(), ec); } void on_complete(error_code&) @@ -240,6 +291,47 @@ private: } }; +/** Create a new parser from a fields parser. + + Associates a Body type with a fields parser, and returns + a new parser which parses a complete message object + containing the original message fields and a new body + of the specified body type. + + This function allows HTTP messages to be parsed in two stages. + First, the fields are parsed and control is returned. Then, + the caller can choose at run-time, the type of Body to + associate with the message. And finally, complete the parse + in a second call. + + @param parser The fields parser to construct from. Ownership + of the message fields in the fields parser is transferred + as if by call to @ref header_parser_v1::release. + + @param args Forwarded to the body constructor of the message + in the new parser. + + @return A parser for a message with the specified @b Body type. + + @par Example + @code + headers_parser ph; + ... + auto p = with_body(ph); + ... + message m = p.release(); + @endcode +*/ +template +parser_v1 +with_body(header_parser_v1& parser, + Args&&... args) +{ + return parser_v1( + parser, std::forward(args)...); +} + } // http } // beast diff --git a/include/beast/http/read.hpp b/include/beast/http/read.hpp index 7e5a09595..67610e658 100644 --- a/include/beast/http/read.hpp +++ b/include/beast/http/read.hpp @@ -8,29 +8,33 @@ #ifndef BEAST_HTTP_READ_HPP #define BEAST_HTTP_READ_HPP -#include -#include #include -#include +#include +#include namespace beast { namespace http { -/** Parse a HTTP/1 message from a stream. +/** Read a HTTP/1 header from a stream. - This function synchronously reads from a stream and passes - data to the specified parser. The call will block until one - of the following conditions are met: + This function is used to synchronously read a header + from a stream. The call blocks until one of the following + conditions is true: - @li A complete message is read in. + @li An entire header is read in. @li An error occurs in the stream or parser. This function is implemented in terms of one or more calls to the stream's `read_some` function. The implementation may read additional octets that lie past the end of the message - being parsed. This additional data is stored in the stream - buffer, which may be used in subsequent calls. + fields being parsed. This additional data is stored in the + stream buffer, which may be used in subsequent calls. + + If the message corresponding to the header being received + contains a message body, it is the callers responsibility + to cause the body to be read in before attempting to read + the next message. @param stream The stream from which the data is to be read. The type must support the @b `SyncReadStream` concept. @@ -41,31 +45,38 @@ namespace http { stream buffer's input sequence will be given to the parser first. - @param parser An object meeting the requirements of Parser - which will receive the data. + @param msg An object used to store the header. Any contents + will be overwritten. The type must support copy assignment + or move assignment. - @throws boost::system::system_error on failure. + @throws system_error Thrown on failure. */ -template +template void -parse(SyncReadStream& stream, - DynamicBuffer& dynabuf, Parser& parser); +read(SyncReadStream& stream, DynamicBuffer& dynabuf, + header& msg); -/** Parse a HTTP/1 message from a stream. +/** Read a HTTP/1 header from a stream. - This function synchronously reads from a stream and passes - data to the specified parser. The call will block until one - of the following conditions are met: + This function is used to synchronously read a header + from a stream. The call blocks until one of the following + conditions is true: - @li A complete message is read in. + @li An entire header is read in. @li An error occurs in the stream or parser. This function is implemented in terms of one or more calls to the stream's `read_some` function. The implementation may read additional octets that lie past the end of the message - being parsed. This additional data is stored in the stream - buffer, which may be used in subsequent calls. + fields being parsed. This additional data is stored in the + stream buffer, which may be used in subsequent calls. + + If the message corresponding to the header being received + contains a message body, it is the callers responsibility + to cause the body to be read in before attempting to read + the next message. @param stream The stream from which the data is to be read. The type must support the @b `SyncReadStream` concept. @@ -76,154 +87,42 @@ parse(SyncReadStream& stream, stream buffer's input sequence will be given to the parser first. - @param parser An object meeting the requirements of `Parser` - which will receive the data. + @param msg An object used to store the header. Any contents + will be overwritten. The type must support copy assignment + or move assignment. @param ec Set to the error, if any occurred. */ -template +template void -parse(SyncReadStream& stream, - DynamicBuffer& dynabuf, Parser& parser, error_code& ec); +read(SyncReadStream& stream, DynamicBuffer& dynabuf, + header& msg, + error_code& ec); -/** Start an asynchronous operation to parse a HTTP/1 message from a stream. +/** Read a HTTP/1 header asynchronously from a stream. - This function is used to asynchronously read from a stream and - pass the data to the specified parser. The function call always - returns immediately. The asynchronous operation will continue - until one of the following conditions is true: + This function is used to asynchronously read a header from + a stream. The function call always returns immediately. The + asynchronous operation will continue until one of the following + conditions is true: - @li A complete message is read in. + @li An entire header is read in. @li An error occurs in the stream or parser. This operation is implemented in terms of one or more calls to - the next layer's `async_read_some` function, and is known as a + the stream's `async_read_some` function, and is known as a composed operation. The program must ensure that the stream performs no other operations until this operation completes. + The implementation may read additional octets that lie past the + end of the message fields being parsed. This additional data is + stored in the stream buffer, which may be used in subsequent calls. - @param stream The stream from which the data is to be read. - The type must support the @b `AsyncReadStream` concept. - - @param dynabuf A @b `DynamicBuffer` holding additional bytes - read by the implementation from the stream. This is both - an input and an output parameter; on entry, any data in the - stream buffer's input sequence will be given to the parser - first. - - @param parser An object meeting the requirements of `Parser` - which will receive the data. This object must remain valid - until the completion handler is invoked. - - @param handler The handler to be called when the request completes. - Copies will be made of the handler as required. The equivalent - function signature of the handler must be: - @code void handler( - error_code const& error // result of operation - ); @endcode - Regardless of whether the asynchronous operation completes - immediately or not, the handler will not be invoked from within - this function. Invocation of the handler will be performed in a - manner equivalent to using `boost::asio::io_service::post`. -*/ -template -#if GENERATING_DOCS -void_or_deduced -#else -typename async_completion< - ReadHandler, void(error_code)>::result_type -#endif -async_parse(AsyncReadStream& stream, DynamicBuffer& dynabuf, - Parser& parser, ReadHandler&& handler); - -/** Read a HTTP/1 message from a stream. - - This function is used to synchronously read a message from - the stream. The call blocks until one of the following conditions - is true: - - @li A complete message is read in. - - @li An error occurs in the stream or parser. - - This function is implemented in terms of one or more calls - to the stream's `read_some` function. The implementation may - read additional octets that lie past the end of the message - being parsed. This additional data is stored in the stream - buffer, which may be used in subsequent calls. - - @param stream The stream from which the data is to be read. - The type must support the @b `SyncReadStream` concept. - - @param dynabuf A @b `DynamicBuffer` holding additional bytes - read by the implementation from the stream. This is both - an input and an output parameter; on entry, any data in the - stream buffer's input sequence will be given to the parser - first. - - @param msg An object used to store the message. Any - contents will be overwritten. - - @throws boost::system::system_error Thrown on failure. -*/ -template -void -read(SyncReadStream& stream, DynamicBuffer& dynabuf, - message_v1& msg); - -/** Read a HTTP/1 message from a stream. - - This function is used to synchronously read a message from - the stream. The call blocks until one of the following conditions - is true: - - @li A complete message is read in. - - @li An error occurs in the stream or parser. - - This function is implemented in terms of one or more calls - to the stream's `read_some` function. The implementation may - read additional octets that lie past the end of the message - being parsed. This additional data is stored in the stream - buffer, which may be used in subsequent calls. - - @param stream The stream from which the data is to be read. - The type must support the @b `SyncReadStream` concept. - - @param dynabuf A @b `DynamicBuffer` holding additional bytes - read by the implementation from the stream. This is both - an input and an output parameter; on entry, any data in the - stream buffer's input sequence will be given to the parser - first. - - @param msg An object used to store the message. Any - contents will be overwritten. - - @param ec Set to the error, if any occurred. -*/ -template -void -read(SyncReadStream& stream, DynamicBuffer& dynabuf, - message_v1& msg, - error_code& ec); - -/** Start an asynchronous operation to read a HTTP/1 message from a stream. - - This function is used to asynchronously read a message from the - stream. The function call always returns immediately. The asynchronous - operation will continue until one of the following conditions is true: - - @li A complete message is read in. - - @li An error occurs in the stream or parser. - - This operation is implemented in terms of one or more calls to the - next layer's `async_read_some` function, and is known as a - composed operation. The program must ensure that the stream - performs no other operations until this operation completes. + If the message corresponding to the header being received + contains a message body, it is the callers responsibility + to cause the body to be read in before attempting to read + the next message. @param stream The stream to read the message from. The type must support the @b `AsyncReadStream` concept. @@ -234,12 +133,14 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf, stream buffer's input sequence will be given to the parser first. - @param msg An object used to store the message. Any contents - will be overwritten. + @param msg An object used to store the header. Any contents + will be overwritten. The type must support copy assignment or + move assignment. The object must remain valid at least until + the completion handler is called; ownership is not transferred. - @param handler The handler to be called when the request completes. - Copies will be made of the handler as required. The equivalent - function signature of the handler must be: + @param handler The handler to be called when the operation + completes. Copies will be made of the handler as required. + The equivalent function signature of the handler must be: @code void handler( error_code const& error // result of operation ); @endcode @@ -249,7 +150,7 @@ read(SyncReadStream& stream, DynamicBuffer& dynabuf, manner equivalent to using `boost::asio::io_service::post`. */ template #if GENERATING_DOCS void_or_deduced @@ -258,7 +159,139 @@ typename async_completion< ReadHandler, void(error_code)>::result_type #endif async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf, - message_v1& msg, + header& msg, + ReadHandler&& handler); + +/** Read a HTTP/1 message from a stream. + + This function is used to synchronously read a message from + a stream. The call blocks until one of the following conditions + is true: + + @li A complete message is read in. + + @li An error occurs in the stream or parser. + + This function is implemented in terms of one or more calls + to the stream's `read_some` function. The implementation may + read additional octets that lie past the end of the message + being parsed. This additional data is stored in the stream + buffer, which may be used in subsequent calls. + + @param stream The stream from which the data is to be read. + The type must support the @b `SyncReadStream` concept. + + @param dynabuf A @b `DynamicBuffer` holding additional bytes + read by the implementation from the stream. This is both + an input and an output parameter; on entry, any data in the + stream buffer's input sequence will be given to the parser + first. + + @param msg An object used to store the message. Any + contents will be overwritten. The type must support + copy assignment or move assignment. + + @throws system_error Thrown on failure. +*/ +template +void +read(SyncReadStream& stream, DynamicBuffer& dynabuf, + message& msg); + +/** Read a HTTP/1 message from a stream. + + This function is used to synchronously read a message from + a stream. The call blocks until one of the following conditions + is true: + + @li A complete message is read in. + + @li An error occurs in the stream or parser. + + This function is implemented in terms of one or more calls + to the stream's `read_some` function. The implementation may + read additional octets that lie past the end of the message + being parsed. This additional data is stored in the stream + buffer, which may be used in subsequent calls. + + @param stream The stream from which the data is to be read. + The type must support the @b `SyncReadStream` concept. + + @param dynabuf A @b `DynamicBuffer` holding additional bytes + read by the implementation from the stream. This is both + an input and an output parameter; on entry, any data in the + stream buffer's input sequence will be given to the parser + first. + + @param msg An object used to store the message. Any + contents will be overwritten. The type must support + copy assignment or move assignment. + + @param ec Set to the error, if any occurred. +*/ +template +void +read(SyncReadStream& stream, DynamicBuffer& dynabuf, + message& msg, + error_code& ec); + +/** Read a HTTP/1 message asynchronously from a stream. + + This function is used to asynchronously read a message from + a stream. The function call always returns immediately. The + asynchronous operation will continue until one of the following + conditions is true: + + @li A complete message is read in. + + @li An error occurs in the stream or parser. + + This operation is implemented in terms of one or more calls to + the stream's `async_read_some` function, and is known as a + composed operation. The program must ensure that the + stream performs no other operations until this operation completes. + The implementation may read additional octets that lie past the + end of the message being parsed. This additional data is stored + in the stream buffer, which may be used in subsequent calls. + + @param stream The stream to read the message from. + The type must support the @b `AsyncReadStream` concept. + + @param dynabuf A @b `DynamicBuffer` holding additional bytes + read by the implementation from the stream. This is both + an input and an output parameter; on entry, any data in the + stream buffer's input sequence will be given to the parser + first. + + @param msg An object used to store the header. Any contents + will be overwritten. The type must support copy assignment or + move assignment. The object must remain valid at least until + the completion handler is called; ownership is not transferred. + + @param handler The handler to be called when the operation + completes. Copies will be made of the handler as required. + The equivalent function signature of the handler must be: + @code void handler( + error_code const& error // result of operation + ); @endcode + Regardless of whether the asynchronous operation completes + immediately or not, the handler will not be invoked from within + this function. Invocation of the handler will be performed in a + manner equivalent to using `boost::asio::io_service::post`. +*/ +template +#if GENERATING_DOCS +void_or_deduced +#else +typename async_completion< + ReadHandler, void(error_code)>::result_type +#endif +async_read(AsyncReadStream& stream, DynamicBuffer& dynabuf, + message& msg, ReadHandler&& handler); } // http diff --git a/include/beast/http/reason.hpp b/include/beast/http/reason.hpp index ab3b51b74..14b9bf7ca 100644 --- a/include/beast/http/reason.hpp +++ b/include/beast/http/reason.hpp @@ -11,7 +11,8 @@ namespace beast { namespace http { -/** Returns the text for a known status code integer. */ +namespace detail { + template char const* reason_string(int status) @@ -66,6 +67,16 @@ reason_string(int status) return ""; } +} // detail + +/** Returns the text for a known status code integer. */ +inline +char const* +reason_string(int status) +{ + return detail::reason_string(status); +} + } // http } // beast diff --git a/include/beast/http/rfc7230.hpp b/include/beast/http/rfc7230.hpp index 3b6f52c4b..15407d0f1 100644 --- a/include/beast/http/rfc7230.hpp +++ b/include/beast/http/rfc7230.hpp @@ -15,22 +15,26 @@ namespace http { /** A list of parameters in a HTTP extension field value. - This container allows iteration of the parameter list - in a HTTP extension. The parameter list is a series - of "name = value" pairs with each pair starting with - a semicolon. - - BNF: - @code - param-list = *( OWS ";" OWS param ) - param = token OWS "=" OWS ( token / quoted-string ) - @endcode + This container allows iteration of the parameter list in a HTTP + extension. The parameter list is a series of name/value pairs + with each pair starting with a semicolon. The value is optional. If a parsing error is encountered while iterating the string, the behavior of the container will be as if a string containing only characters up to but excluding the first invalid character was used to construct the list. + @par BNF + @code + param-list = *( OWS ";" OWS param ) + param = token OWS [ "=" OWS ( token / quoted-string ) ] + @endcode + + To use this class, construct with the string to be parsed and + then use @ref begin and @ref end, or range-for to iterate each + item: + + @par Example @code for(auto const& param : param_list{";level=9;no_context_takeover;bits=15"}) { @@ -48,8 +52,9 @@ class param_list public: /** The type of each element in the list. - The first string in the pair is the name of the - parameter, and the second string in the pair is its value. + The first string in the pair is the name of the parameter, + and the second string in the pair is its value (which may + be empty). */ using value_type = std::pair; @@ -96,23 +101,24 @@ public: field value. The extension list is a comma separated list of token parameter list pairs. - BNF: - @code - ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] ) - ext = token param-list - param-list = *( OWS ";" OWS param ) - param = token OWS "=" OWS ( token / quoted-string ) - @endcode - If a parsing error is encountered while iterating the string, the behavior of the container will be as if a string containing only characters up to but excluding the first invalid character was used to construct the list. + @par BNF + @code + ext-list = *( "," OWS ) ext *( OWS "," [ OWS ext ] ) + ext = token param-list + param-list = *( OWS ";" OWS param ) + param = token OWS [ "=" OWS ( token / quoted-string ) ] + @endcode + To use this class, construct with the string to be parsed and - then use @ref begin and @end, or range-for to iterate each + then use @ref begin and @ref end, or range-for to iterate each item: + @par Example @code for(auto const& ext : ext_list{"none, 7z;level=9, zip;no_context_takeover;bits=15"}) { @@ -196,24 +202,25 @@ public: /** A list of tokens in a comma separated HTTP field value. - This container allows iteration of the extensions in a HTTP - field value. The extension list is a comma separated list of - token parameter list pairs. - - BNF: - @code - token-list = *( "," OWS ) token *( OWS "," [ OWS ext ] ) - @endcode + This container allows iteration of a list of items in a + header field value. The input is a comma separated list of + tokens. If a parsing error is encountered while iterating the string, the behavior of the container will be as if a string containing only characters up to but excluding the first invalid character was used to construct the list. + @par BNF + @code + token-list = *( "," OWS ) token *( OWS "," [ OWS token ] ) + @endcode + To use this class, construct with the string to be parsed and - then use @ref begin and @end, or range-for to iterate each + then use @ref begin and @ref end, or range-for to iterate each item: + @par Example @code for(auto const& token : token_list{"apple, pear, banana"}) std::cout << token << "\n"; @@ -226,12 +233,7 @@ class token_list boost::string_ref s_; public: - /** The type of each element in the token list. - - The first element of the pair is the extension token, and the - second element of the pair is an iterable container holding the - extension's name/value parameters. - */ + /// The type of each element in the token list. using value_type = boost::string_ref; /// A constant iterator to the list @@ -279,4 +281,3 @@ public: #include #endif - diff --git a/include/beast/http/string_body.hpp b/include/beast/http/string_body.hpp index 76e46a05b..5b8101c75 100644 --- a/include/beast/http/string_body.hpp +++ b/include/beast/http/string_body.hpp @@ -8,8 +8,12 @@ #ifndef BEAST_HTTP_STRING_BODY_HPP #define BEAST_HTTP_STRING_BODY_HPP -#include +#include +#include +#include +#include #include +#include #include #include @@ -34,14 +38,19 @@ private: value_type& s_; public: - template + template explicit reader(message& m) noexcept + string_body, Fields>& m) noexcept : s_(m.body) { } + void + init(error_code&) noexcept + { + } + void write(void const* data, std::size_t size, error_code&) noexcept @@ -57,33 +66,32 @@ private: value_type const& body_; public: - writer(writer const&) = delete; - writer& operator=(writer const&) = delete; - - template + template explicit writer(message< - isRequest, string_body, Headers> const& msg) + isRequest, string_body, Fields> const& msg) noexcept : body_(msg.body) { } void - init(error_code& ec) + init(error_code& ec) noexcept { + beast::detail::ignore_unused(ec); } std::uint64_t - content_length() const + content_length() const noexcept { return body_.size(); } - template + template boost::tribool - operator()(resume_context&&, error_code&, Write&& write) + write(resume_context&&, error_code&, + WriteFunction&& wf) noexcept { - write(boost::asio::buffer(body_)); + wf(boost::asio::buffer(body_)); return true; } }; diff --git a/include/beast/http/write.hpp b/include/beast/http/write.hpp index 9a79f3131..f27937bdc 100644 --- a/include/beast/http/write.hpp +++ b/include/beast/http/write.hpp @@ -8,7 +8,7 @@ #ifndef BEAST_HTTP_WRITE_HPP #define BEAST_HTTP_WRITE_HPP -#include +#include #include #include #include @@ -17,12 +17,127 @@ namespace beast { namespace http { -/** Write a HTTP/1 message on a stream. +/** Write a HTTP/1 header to a stream. + + This function is used to synchronously write a header to + a stream. The call will block until one of the following + conditions is true: + + @li The entire header is written. + + @li An error occurs. + + This operation is implemented in terms of one or more calls + to the stream's `write_some` function. + + Regardless of the semantic meaning of the header (for example, + specifying "Content-Length: 0" and "Connection: close"), + this function will not return `boost::asio::error::eof`. + + @param stream The stream to which the data is to be written. + The type must support the @b `SyncWriteStream` concept. + + @param msg The header to write. + + @throws system_error Thrown on failure. +*/ +template +void +write(SyncWriteStream& stream, + header const& msg); + +/** Write a HTTP/1 header to a stream. + + This function is used to synchronously write a header to + a stream. The call will block until one of the following + conditions is true: + + @li The entire header is written. + + @li An error occurs. + + This operation is implemented in terms of one or more calls + to the stream's `write_some` function. + + Regardless of the semantic meaning of the header (for example, + specifying "Content-Length: 0" and "Connection: close"), + this function will not return `boost::asio::error::eof`. + + @param stream The stream to which the data is to be written. + The type must support the @b `SyncWriteStream` concept. + + @param msg The header to write. + + @param ec Set to the error, if any occurred. +*/ +template +void +write(SyncWriteStream& stream, + header const& msg, + error_code& ec); + +/** Write a HTTP/1 header asynchronously to a stream. + + This function is used to asynchronously write a header to + a stream. The function call always returns immediately. The + asynchronous operation will continue until one of the following + conditions is true: + + @li The entire header is written. + + @li An error occurs. + + This operation is implemented in terms of one or more calls to + the stream's `async_write_some` functions, and is known as a + composed operation. The program must ensure that the + stream performs no other write operations until this operation + completes. + + Regardless of the semantic meaning of the header (for example, + specifying "Content-Length: 0" and "Connection: close"), + this function will not return `boost::asio::error::eof`. + + @param stream The stream to which the data is to be written. + The type must support the @b `AsyncWriteStream` concept. + + @param msg The header to write. The object must remain valid + at least until the completion handler is called; ownership is + not transferred. + + @param handler The handler to be called when the operation + completes. Copies will be made of the handler as required. + The equivalent function signature of the handler must be: + @code void handler( + error_code const& error // result of operation + ); @endcode + Regardless of whether the asynchronous operation completes + immediately or not, the handler will not be invoked from within + this function. Invocation of the handler will be performed in a + manner equivalent to using `boost::asio::io_service::post`. +*/ +template +#if GENERATING_DOCS +void_or_deduced +#else +typename async_completion< + WriteHandler, void(error_code)>::result_type +#endif +async_write(AsyncWriteStream& stream, + header const& msg, + WriteHandler&& handler); + +//------------------------------------------------------------------------------ + +/** Write a HTTP/1 message to a stream. This function is used to write a message to a stream. The call will block until one of the following conditions is true: - @li The entire message is sent. + @li The entire message is written. @li An error occurs. @@ -40,20 +155,20 @@ namespace http { @param msg The message to write. - @throws boost::system::error Thrown on failure. + @throws system_error Thrown on failure. */ template + bool isRequest, class Body, class Fields> void write(SyncWriteStream& stream, - message_v1 const& msg); + message const& msg); /** Write a HTTP/1 message on a stream. This function is used to write a message to a stream. The call will block until one of the following conditions is true: - @li The entire message is sent. + @li The entire message is written. @li An error occurs. @@ -74,28 +189,28 @@ write(SyncWriteStream& stream, @param ec Set to the error, if any occurred. */ template + bool isRequest, class Body, class Fields> void write(SyncWriteStream& stream, - message_v1 const& msg, + message const& msg, error_code& ec); -/** Start an asynchronous operation to write a HTTP/1 message to a stream. +/** Write a HTTP/1 message asynchronously to a stream. - This function is used to asynchronously write a message to a stream. - The function call always returns immediately. The asynchronous - operation will continue until one of the following conditions is true: + This function is used to asynchronously write a message to + a stream. The function call always returns immediately. The + asynchronous operation will continue until one of the following + conditions is true: - @li The entire message is sent. + @li The entire message is written. @li An error occurs. - This operation is implemented in terms of one or more calls to the - stream's `async_write_some` functions, and is known as a composed - operation. The program must ensure that the stream performs no - other write operations (such as @ref async_write, the stream's - `async_write_some` function, or any other composed operations that - perform writes) until this operation completes. + This operation is implemented in terms of one or more calls to + the stream's `async_write_some` functions, and is known as a + composed operation. The program must ensure that the + stream performs no other write operations until this operation + completes. The implementation will automatically perform chunk encoding if the contents of the message indicate that chunk encoding is required. @@ -106,11 +221,13 @@ write(SyncWriteStream& stream, @param stream The stream to which the data is to be written. The type must support the @b `AsyncWriteStream` concept. - @param msg The message to send. + @param msg The message to write. The object must remain valid + at least until the completion handler is called; ownership is + not transferred. - @param handler The handler to be called when the request completes. - Copies will be made of the handler as required. The equivalent - function signature of the handler must be: + @param handler The handler to be called when the operation + completes. Copies will be made of the handler as required. + The equivalent function signature of the handler must be: @code void handler( error_code const& error // result of operation ); @endcode @@ -118,12 +235,9 @@ write(SyncWriteStream& stream, immediately or not, the handler will not be invoked from within this function. Invocation of the handler will be performed in a manner equivalent to using `boost::asio::io_service::post`. - - @note The message object must remain valid at least until the - completion handler is called, no copies are made. */ template #if GENERATING_DOCS void_or_deduced @@ -132,10 +246,26 @@ typename async_completion< WriteHandler, void(error_code)>::result_type #endif async_write(AsyncWriteStream& stream, - message_v1 const& msg, + message const& msg, WriteHandler&& handler); -/** Serialize a HTTP/1 message to an ostream. +//------------------------------------------------------------------------------ + +/** Serialize a HTTP/1 header to a `std::ostream`. + + The function converts the header to its HTTP/1 serialized + representation and stores the result in the output stream. + + @param os The output stream to write to. + + @param msg The message fields to write. +*/ +template +std::ostream& +operator<<(std::ostream& os, + header const& msg); + +/** Serialize a HTTP/1 message to a `std::ostream`. The function converts the message to its HTTP/1 serialized representation and stores the result in the output stream. @@ -143,14 +273,14 @@ async_write(AsyncWriteStream& stream, The implementation will automatically perform chunk encoding if the contents of the message indicate that chunk encoding is required. - @param os The ostream to write to. + @param os The output stream to write to. @param msg The message to write. */ -template +template std::ostream& operator<<(std::ostream& os, - message_v1 const& msg); + message const& msg); } // http } // beast diff --git a/include/beast/version.hpp b/include/beast/version.hpp index feb17e679..7d02e3293 100644 --- a/include/beast/version.hpp +++ b/include/beast/version.hpp @@ -16,6 +16,6 @@ // #define BEAST_VERSION 100000 -#define BEAST_VERSION_STRING "1.0.0-b13" +#define BEAST_VERSION_STRING "1.0.0-b22" #endif diff --git a/include/beast/websocket/detail/decorator.hpp b/include/beast/websocket/detail/decorator.hpp index c0492477b..1250d35b1 100644 --- a/include/beast/websocket/detail/decorator.hpp +++ b/include/beast/websocket/detail/decorator.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include namespace beast { @@ -40,6 +41,32 @@ class decorator : public abstract_decorator { T t_; + class call_req_possible + { + template().operator()( + std::declval()), + std::true_type{})> + static R check(int); + template + static std::false_type check(...); + public: + using type = decltype(check(0)); + }; + + class call_res_possible + { + template().operator()( + std::declval()), + std::true_type{})> + static R check(int); + template + static std::false_type check(...); + public: + using type = decltype(check(0)); + }; + public: decorator() = default; @@ -56,38 +83,45 @@ public: void operator()(request_type& req) override { - t_(req); + (*this)(req, typename call_req_possible::type{}); } void operator()(response_type& resp) override { - t_(resp); + (*this)(resp, typename call_res_possible::type{}); + } + +private: + void + operator()(request_type& req, std::true_type) + { + t_(req); + } + + void + operator()(request_type& req, std::false_type) + { + req.fields.replace("User-Agent", + std::string{"Beast/"} + BEAST_VERSION_STRING); + } + + void + operator()(response_type& res, std::true_type) + { + t_(res); + } + + void + operator()(response_type& res, std::false_type) + { + res.fields.replace("Server", + std::string{"Beast/"} + BEAST_VERSION_STRING); } }; struct default_decorator { - static - char const* - version() - { - return "Beast.WSProto/1.0"; - } - - template - void - operator()(http::message& req) - { - req.headers.replace("User-Agent", version()); - } - - template - void - operator()(http::message& resp) - { - resp.headers.replace("Server", version()); - } }; using decorator_type = diff --git a/include/beast/websocket/detail/error.hpp b/include/beast/websocket/detail/error.hpp deleted file mode 100644 index 5aa1cf749..000000000 --- a/include/beast/websocket/detail/error.hpp +++ /dev/null @@ -1,92 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_WEBSOCKET_DETAIL_ERROR_HPP -#define BEAST_WEBSOCKET_DETAIL_ERROR_HPP - -#include - -namespace boost { -namespace system { -template<> -struct is_error_code_enum -{ - static bool const value = true; -}; -} // system -} // boost - -namespace beast { -namespace websocket { -namespace detail { - -class error_category : public boost::system::error_category -{ -public: - const char* - name() const noexcept override - { - return "websocket"; - } - - std::string - message(int ev) const override - { - switch(static_cast(ev)) - { - case error::closed: return "WebSocket connection closed normally"; - case error::failed: return "WebSocket connection failed due to a protocol violation"; - case error::handshake_failed: return "WebSocket Upgrade handshake failed"; - case error::keep_alive: return "WebSocket Upgrade handshake failed but connection is still open"; - - case error::response_malformed: return "malformed HTTP response"; - case error::response_failed: return "upgrade request failed"; - case error::response_denied: return "upgrade request denied"; - case error::request_malformed: return "malformed HTTP request"; - case error::request_invalid: return "upgrade request invalid"; - case error::request_denied: return "upgrade request denied"; - default: - return "websocket error"; - } - } - - boost::system::error_condition - default_error_condition(int ev) const noexcept override - { - return boost::system::error_condition(ev, *this); - } - - bool - equivalent(int ev, - boost::system::error_condition const& condition - ) const noexcept override - { - return condition.value() == ev && - &condition.category() == this; - } - - bool - equivalent(error_code const& error, int ev) const noexcept override - { - return error.value() == ev && - &error.category() == this; - } -}; - -inline -boost::system::error_category const& -get_error_category() -{ - static detail::error_category const cat{}; - return cat; -} - -} // detail -} // websocket -} // beast - -#endif diff --git a/include/beast/websocket/detail/frame.hpp b/include/beast/websocket/detail/frame.hpp index 672d11c14..3fece7b13 100644 --- a/include/beast/websocket/detail/frame.hpp +++ b/include/beast/websocket/detail/frame.hpp @@ -15,24 +15,14 @@ #include #include #include +#include #include -#include #include namespace beast { namespace websocket { namespace detail { -/// Identifies the role of a WebSockets stream. -enum class role_type -{ - /// Stream is operating as a client. - client, - - /// Stream is operating as a server. - server -}; - // Contents of a WebSocket frame header struct frame_header { @@ -163,134 +153,6 @@ write(DynamicBuffer& db, frame_header const& fh) db.prepare(n), buffer(b))); } -// Read fixed frame header -// Requires at least 2 bytes -// -template -std::size_t -read_fh1(frame_header& fh, DynamicBuffer& db, - role_type role, close_code::value& code) -{ - using boost::asio::buffer; - using boost::asio::buffer_copy; - using boost::asio::buffer_size; - std::uint8_t b[2]; - assert(buffer_size(db.data()) >= sizeof(b)); - db.consume(buffer_copy(buffer(b), db.data())); - std::size_t need; - fh.len = b[1] & 0x7f; - switch(fh.len) - { - case 126: need = 2; break; - case 127: need = 8; break; - default: - need = 0; - } - fh.mask = (b[1] & 0x80) != 0; - if(fh.mask) - need += 4; - fh.op = static_cast(b[0] & 0x0f); - fh.fin = (b[0] & 0x80) != 0; - fh.rsv1 = (b[0] & 0x40) != 0; - fh.rsv2 = (b[0] & 0x20) != 0; - fh.rsv3 = (b[0] & 0x10) != 0; - // invalid length for control message - if(is_control(fh.op) && fh.len > 125) - { - code = close_code::protocol_error; - return 0; - } - // reserved bits not cleared - if(fh.rsv1 || fh.rsv2 || fh.rsv3) - { - code = close_code::protocol_error; - return 0; - } - // reserved opcode - if(is_reserved(fh.op)) - { - code = close_code::protocol_error; - return 0; - } - // fragmented control message - if(is_control(fh.op) && ! fh.fin) - { - code = close_code::protocol_error; - return 0; - } - // unmasked frame from client - if(role == role_type::server && ! fh.mask) - { - code = close_code::protocol_error; - return 0; - } - // masked frame from server - if(role == role_type::client && fh.mask) - { - code = close_code::protocol_error; - return 0; - } - code = close_code::none; - return need; -} - -// Decode variable frame header from stream -// -template -void -read_fh2(frame_header& fh, DynamicBuffer& db, - role_type role, close_code::value& code) -{ - using boost::asio::buffer; - using boost::asio::buffer_copy; - using boost::asio::buffer_size; - using namespace boost::endian; - switch(fh.len) - { - case 126: - { - std::uint8_t b[2]; - assert(buffer_size(db.data()) >= sizeof(b)); - db.consume(buffer_copy(buffer(b), db.data())); - fh.len = big_uint16_to_native(&b[0]); - // length not canonical - if(fh.len < 126) - { - code = close_code::protocol_error; - return; - } - break; - } - case 127: - { - std::uint8_t b[8]; - assert(buffer_size(db.data()) >= sizeof(b)); - db.consume(buffer_copy(buffer(b), db.data())); - fh.len = big_uint64_to_native(&b[0]); - // length not canonical - if(fh.len < 65536) - { - code = close_code::protocol_error; - return; - } - break; - } - } - if(fh.mask) - { - std::uint8_t b[4]; - assert(buffer_size(db.data()) >= sizeof(b)); - db.consume(buffer_copy(buffer(b), db.data())); - fh.key = little_uint32_to_native(&b[0]); - } - else - { - // initialize this otherwise operator== breaks - fh.key = 0; - } - code = close_code::none; -} - // Read data from buffers // This is for ping and pong payloads // @@ -301,7 +163,7 @@ read(ping_data& data, Buffers const& bs) using boost::asio::buffer_copy; using boost::asio::buffer_size; using boost::asio::mutable_buffers_1; - assert(buffer_size(bs) <= data.max_size()); + BOOST_ASSERT(buffer_size(bs) <= data.max_size()); data.resize(buffer_size(bs)); buffer_copy(mutable_buffers_1{ data.data(), data.size()}, bs); @@ -320,7 +182,7 @@ read(close_reason& cr, using boost::asio::buffer_size; using namespace boost::endian; auto n = buffer_size(bs); - assert(n <= 125); + BOOST_ASSERT(n <= 125); if(n == 0) { cr = close_reason{}; diff --git a/include/beast/websocket/detail/hybi13.hpp b/include/beast/websocket/detail/hybi13.hpp index 154e85820..b7ecb66a1 100644 --- a/include/beast/websocket/detail/hybi13.hpp +++ b/include/beast/websocket/detail/hybi13.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -23,15 +24,17 @@ template std::string make_sec_ws_key(Gen& g) { - union U + std::array a; + for(int i = 0; i < 16; i += 4) { - std::array a4; - std::array a16; - }; - U u; - for(int i = 0; i < 4; ++i) - u.a4[i] = g(); - return beast::detail::base64_encode(u.a16.data(), u.a16.size()); + auto const v = g(); + a[i ] = v & 0xff; + a[i+1] = (v >> 8) & 0xff; + a[i+2] = (v >> 16) & 0xff; + a[i+3] = (v >> 24) & 0xff; + } + return beast::detail::base64_encode( + a.data(), a.size()); } template diff --git a/include/beast/websocket/detail/invokable.hpp b/include/beast/websocket/detail/invokable.hpp index df5b46de3..7fcfc2cf9 100644 --- a/include/beast/websocket/detail/invokable.hpp +++ b/include/beast/websocket/detail/invokable.hpp @@ -8,8 +8,9 @@ #ifndef BEAST_WEBSOCKET_DETAIL_INVOKABLE_HPP #define BEAST_WEBSOCKET_DETAIL_INVOKABLE_HPP +#include +#include #include -#include #include #include #include @@ -64,8 +65,19 @@ class invokable struct exemplar { - std::shared_ptr _; - void operator()(){} + struct H + { + void operator()(); + }; + + struct T + { + using handler_type = H; + }; + + handler_ptr hp; + + void operator()(); }; using buf_type = char[sizeof(holder)]; @@ -74,15 +86,11 @@ class invokable alignas(holder) buf_type buf_; public: -#ifndef NDEBUG ~invokable() { - // Engaged invokables must be invoked before - // destruction otherwise the io_service - // invariants are broken w.r.t completions. - assert(! base_); + if(base_) + base_->~base(); } -#endif invokable() = default; @@ -102,7 +110,7 @@ public: // Engaged invokables must be invoked before // assignment otherwise the io_service // invariants are broken w.r.t completions. - assert(! base_); + BOOST_ASSERT(! base_); if(other.base_) { @@ -135,7 +143,7 @@ invokable::emplace(F&& f) { static_assert(sizeof(buf_type) >= sizeof(holder), "buffer too small"); - assert(! base_); + BOOST_ASSERT(! base_); ::new(buf_) holder(std::forward(f)); base_ = reinterpret_cast(&buf_[0]); } diff --git a/include/beast/websocket/detail/mask.hpp b/include/beast/websocket/detail/mask.hpp index fb67b511e..02ca38fda 100644 --- a/include/beast/websocket/detail/mask.hpp +++ b/include/beast/websocket/detail/mask.hpp @@ -67,7 +67,9 @@ maskgen_t<_>::rekey() g_.seed(ss); } -using maskgen = maskgen_t; +// VFALCO NOTE This generator has 5KB of state! +//using maskgen = maskgen_t; +using maskgen = maskgen_t; //------------------------------------------------------------------------------ @@ -103,73 +105,119 @@ ror(T t, unsigned n = 1) static_cast::type>(t) >> n)); } -// 32-bit Unoptimized +// 32-bit optimized // template void -mask_inplace_general( +mask_inplace_fast( boost::asio::mutable_buffer const& b, std::uint32_t& key) { using boost::asio::buffer_cast; using boost::asio::buffer_size; - auto const n = buffer_size(b); + auto n = buffer_size(b); auto p = buffer_cast(b); + if(n >= sizeof(key)) + { + // Bring p to 4-byte alignment + auto const i = reinterpret_cast< + std::uintptr_t>(p) & (sizeof(key)-1); + switch(i) + { + case 1: p[2] ^= static_cast(key >> 16); + case 2: p[1] ^= static_cast(key >> 8); + case 3: p[0] ^= static_cast(key); + { + auto const d = static_cast< + unsigned>(sizeof(key) - i); + key = ror(key, 8*d); + n -= d; + p += d; + } + default: + break; + } + } + + // Mask 4 bytes at a time for(auto i = n / sizeof(key); i; --i) { - *p ^= key ; ++p; - *p ^= (key >> 8); ++p; - *p ^= (key >>16); ++p; - *p ^= (key >>24); ++p; + *reinterpret_cast< + std::uint32_t*>(p) ^= key; + p += sizeof(key); } - auto const m = - static_cast(n % sizeof(key)); - switch(m) + + // Leftovers + n &= sizeof(key)-1; + switch(n) { - case 3: p[2] ^= (key >>16); - case 2: p[1] ^= (key >> 8); - case 1: p[0] ^= key; - key = ror(key, m*8); + case 3: p[2] ^= static_cast(key >> 16); + case 2: p[1] ^= static_cast(key >> 8); + case 1: p[0] ^= static_cast(key); + key = ror(key, static_cast(8*n)); default: break; } } -// 64-bit unoptimized +// 64-bit optimized // template void -mask_inplace_general( +mask_inplace_fast( boost::asio::mutable_buffer const& b, std::uint64_t& key) { using boost::asio::buffer_cast; using boost::asio::buffer_size; - auto const n = buffer_size(b); + auto n = buffer_size(b); auto p = buffer_cast(b); + if(n >= sizeof(key)) + { + // Bring p to 8-byte alignment + auto const i = reinterpret_cast< + std::uintptr_t>(p) & (sizeof(key)-1); + switch(i) + { + case 1: p[6] ^= static_cast(key >> 48); + case 2: p[5] ^= static_cast(key >> 40); + case 3: p[4] ^= static_cast(key >> 32); + case 4: p[3] ^= static_cast(key >> 24); + case 5: p[2] ^= static_cast(key >> 16); + case 6: p[1] ^= static_cast(key >> 8); + case 7: p[0] ^= static_cast(key); + { + auto const d = static_cast< + unsigned>(sizeof(key) - i); + key = ror(key, 8*d); + n -= d; + p += d; + } + default: + break; + } + } + + // Mask 8 bytes at a time for(auto i = n / sizeof(key); i; --i) { - *p ^= key ; ++p; - *p ^= (key >> 8); ++p; - *p ^= (key >>16); ++p; - *p ^= (key >>24); ++p; - *p ^= (key >>32); ++p; - *p ^= (key >>40); ++p; - *p ^= (key >>48); ++p; - *p ^= (key >>56); ++p; + *reinterpret_cast< + std::uint64_t*>(p) ^= key; + p += sizeof(key); } - auto const m = - static_cast(n % sizeof(key)); - switch(m) + + // Leftovers + n &= sizeof(key)-1; + switch(n) { - case 7: p[6] ^= (key >>16); - case 6: p[5] ^= (key >> 8); - case 5: p[4] ^= key; - case 4: p[3] ^= (key >>24); - case 3: p[2] ^= (key >>16); - case 2: p[1] ^= (key >> 8); - case 1: p[0] ^= key; - key = ror(key, m*8); + case 7: p[6] ^= static_cast(key >> 48); + case 6: p[5] ^= static_cast(key >> 40); + case 5: p[4] ^= static_cast(key >> 32); + case 4: p[3] ^= static_cast(key >> 24); + case 3: p[2] ^= static_cast(key >> 16); + case 2: p[1] ^= static_cast(key >> 8); + case 1: p[0] ^= static_cast(key); + key = ror(key, static_cast(8*n)); default: break; } @@ -181,7 +229,7 @@ mask_inplace( boost::asio::mutable_buffer const& b, std::uint32_t& key) { - mask_inplace_general(b, key); + mask_inplace_fast(b, key); } inline @@ -190,7 +238,7 @@ mask_inplace( boost::asio::mutable_buffer const& b, std::uint64_t& key) { - mask_inplace_general(b, key); + mask_inplace_fast(b, key); } // Apply mask in place diff --git a/include/beast/websocket/detail/stream_base.hpp b/include/beast/websocket/detail/stream_base.hpp index 5d66747fb..2256d1403 100644 --- a/include/beast/websocket/detail/stream_base.hpp +++ b/include/beast/websocket/detail/stream_base.hpp @@ -9,6 +9,7 @@ #define BEAST_WEBSOCKET_DETAIL_STREAM_BASE_HPP #include +#include #include #include #include @@ -19,74 +20,107 @@ #include #include #include -#include +#include #include -#include -#include #include namespace beast { namespace websocket { namespace detail { -template -static -std::size_t -clamp(UInt x) +/// Identifies the role of a WebSockets stream. +enum class role_type { - if(x >= std::numeric_limits::max()) - return std::numeric_limits::max(); - return static_cast(x); -} + /// Stream is operating as a client. + client, -template -static -std::size_t -clamp(UInt x, std::size_t limit) -{ - if(x >= limit) - return limit; - return static_cast(x); -} - -using pong_cb = std::function; + /// Stream is operating as a server. + server +}; //------------------------------------------------------------------------------ struct stream_base { protected: + friend class frame_test; + struct op {}; - detail::maskgen maskgen_; // source of mask keys - decorator_type d_; // adorns http messages - bool keep_alive_ = false; // close on failed upgrade + detail::maskgen maskgen_; // source of mask keys + decorator_type d_; // adorns http messages + bool keep_alive_ = false; // close on failed upgrade std::size_t rd_msg_max_ = - 16 * 1024 * 1024; // max message size - std::size_t - wr_frag_size_ = 16 * 1024; // size of auto-fragments - std::size_t mask_buf_size_ = 4096; // mask buffer size - opcode wr_opcode_ = opcode::text; // outgoing message type - pong_cb pong_cb_; // pong callback - role_type role_; // server or client - bool failed_; // the connection failed + 16 * 1024 * 1024; // max message size + bool wr_autofrag_ = true; // auto fragment + std::size_t wr_buf_size_ = 4096; // mask buffer size + opcode wr_opcode_ = opcode::text; // outgoing message type + pong_cb pong_cb_; // pong callback + role_type role_; // server or client + bool failed_; // the connection failed - detail::frame_header rd_fh_; // current frame header - detail::prepared_key_type rd_key_; // prepared masking key - detail::utf8_checker rd_utf8_check_;// for current text msg - std::uint64_t rd_size_; // size of the current message so far - std::uint64_t rd_need_ = 0; // bytes left in msg frame payload - opcode rd_opcode_; // opcode of current msg - bool rd_cont_; // expecting a continuation frame + detail::frame_header rd_fh_; // current frame header + detail::prepared_key_type rd_key_; // prepared masking key + detail::utf8_checker rd_utf8_check_; // for current text msg + std::uint64_t rd_size_; // size of the current message so far + std::uint64_t rd_need_ = 0; // bytes left in msg frame payload + opcode rd_opcode_; // opcode of current msg + bool rd_cont_; // expecting a continuation frame - bool wr_close_; // sent close frame - bool wr_cont_; // next write is continuation frame - op* wr_block_; // op currenly writing + bool wr_close_; // sent close frame + op* wr_block_; // op currenly writing - ping_data* pong_data_; // where to put pong payload - invokable rd_op_; // invoked after write completes - invokable wr_op_; // invoked after read completes - close_reason cr_; // set from received close frame + ping_data* pong_data_; // where to put pong payload + invokable rd_op_; // invoked after write completes + invokable wr_op_; // invoked after read completes + close_reason cr_; // set from received close frame + + // State information for the message being sent + // + struct wr_t + { + // `true` if next frame is a continuation, + // `false` if next frame starts a new message + bool cont; + + // `true` if this message should be auto-fragmented + // This gets set to the auto-fragment option at the beginning + // of sending a message, so that the option can be changed + // mid-send without affecting the current message. + bool autofrag; + + // `true` if this message should be compressed. + // This gets set to the compress option at the beginning of + // of sending a message, so that the option can be changed + // mid-send without affecting the current message. + bool compress; + + // Size of the write buffer. + // This gets set to the write buffer size option at the + // beginning of sending a message, so that the option can be + // changed mid-send without affecting the current message. + std::size_t size; + + // The write buffer. + // The buffer is allocated or reallocated at the beginning of + // sending a message. + std::unique_ptr buf; + + void + open() + { + cont = false; + size = 0; + } + + void + close() + { + buf.reset(); + } + }; + + wr_t wr_; stream_base(stream_base&&) = default; stream_base(stream_base const&) = delete; @@ -104,7 +138,19 @@ protected: template void - prepare_fh(close_code::value& code); + close(); + + template + std::size_t + read_fh1(DynamicBuffer& db, close_code::value& code); + + template + void + read_fh2(DynamicBuffer& db, close_code::value& code); + + template + void + wr_prepare(bool compress); template void @@ -115,6 +161,321 @@ protected: write_ping(DynamicBuffer& db, opcode op, ping_data const& data); }; +template +void +stream_base:: +open(role_type role) +{ + // VFALCO TODO analyze and remove dupe code in reset() + role_ = role; + failed_ = false; + rd_need_ = 0; + rd_cont_ = false; + wr_close_ = false; + wr_block_ = nullptr; // should be nullptr on close anyway + pong_data_ = nullptr; // should be nullptr on close anyway + + wr_.open(); +} + +template +void +stream_base:: +close() +{ + wr_.close(); +} + +// Read fixed frame header +// Requires at least 2 bytes +// +template +std::size_t +stream_base:: +read_fh1(DynamicBuffer& db, close_code::value& code) +{ + using boost::asio::buffer; + using boost::asio::buffer_copy; + using boost::asio::buffer_size; + auto const err = + [&](close_code::value cv) + { + code = cv; + return 0; + }; + std::uint8_t b[2]; + assert(buffer_size(db.data()) >= sizeof(b)); + db.consume(buffer_copy(buffer(b), db.data())); + std::size_t need; + rd_fh_.len = b[1] & 0x7f; + switch(rd_fh_.len) + { + case 126: need = 2; break; + case 127: need = 8; break; + default: + need = 0; + } + rd_fh_.mask = (b[1] & 0x80) != 0; + if(rd_fh_.mask) + need += 4; + rd_fh_.op = static_cast(b[0] & 0x0f); + rd_fh_.fin = (b[0] & 0x80) != 0; + rd_fh_.rsv1 = (b[0] & 0x40) != 0; + rd_fh_.rsv2 = (b[0] & 0x20) != 0; + rd_fh_.rsv3 = (b[0] & 0x10) != 0; + switch(rd_fh_.op) + { + case opcode::binary: + case opcode::text: + if(rd_cont_) + { + // new data frame when continuation expected + return err(close_code::protocol_error); + } + if(rd_fh_.rsv1 || rd_fh_.rsv2 || rd_fh_.rsv3) + { + // reserved bits not cleared + return err(close_code::protocol_error); + } + break; + + case opcode::cont: + if(! rd_cont_) + { + // continuation without an active message + return err(close_code::protocol_error); + } + if(rd_fh_.rsv1 || rd_fh_.rsv2 || rd_fh_.rsv3) + { + // reserved bits not cleared + return err(close_code::protocol_error); + } + break; + + default: + if(is_reserved(rd_fh_.op)) + { + // reserved opcode + return err(close_code::protocol_error); + } + if(! rd_fh_.fin) + { + // fragmented control message + return err(close_code::protocol_error); + } + if(rd_fh_.len > 125) + { + // invalid length for control message + return err(close_code::protocol_error); + } + if(rd_fh_.rsv1 || rd_fh_.rsv2 || rd_fh_.rsv3) + { + // reserved bits not cleared + return err(close_code::protocol_error); + } + break; + } + // unmasked frame from client + if(role_ == role_type::server && ! rd_fh_.mask) + { + code = close_code::protocol_error; + return 0; + } + // masked frame from server + if(role_ == role_type::client && rd_fh_.mask) + { + code = close_code::protocol_error; + return 0; + } + code = close_code::none; + return need; +} + +// Decode variable frame header from stream +// +template +void +stream_base:: +read_fh2(DynamicBuffer& db, close_code::value& code) +{ + using boost::asio::buffer; + using boost::asio::buffer_copy; + using boost::asio::buffer_size; + using namespace boost::endian; + switch(rd_fh_.len) + { + case 126: + { + std::uint8_t b[2]; + assert(buffer_size(db.data()) >= sizeof(b)); + db.consume(buffer_copy(buffer(b), db.data())); + rd_fh_.len = big_uint16_to_native(&b[0]); + // length not canonical + if(rd_fh_.len < 126) + { + code = close_code::protocol_error; + return; + } + break; + } + case 127: + { + std::uint8_t b[8]; + assert(buffer_size(db.data()) >= sizeof(b)); + db.consume(buffer_copy(buffer(b), db.data())); + rd_fh_.len = big_uint64_to_native(&b[0]); + // length not canonical + if(rd_fh_.len < 65536) + { + code = close_code::protocol_error; + return; + } + break; + } + } + if(rd_fh_.mask) + { + std::uint8_t b[4]; + assert(buffer_size(db.data()) >= sizeof(b)); + db.consume(buffer_copy(buffer(b), db.data())); + rd_fh_.key = little_uint32_to_native(&b[0]); + } + else + { + // initialize this otherwise operator== breaks + rd_fh_.key = 0; + } + if(rd_fh_.mask) + prepare_key(rd_key_, rd_fh_.key); + if(! is_control(rd_fh_.op)) + { + if(rd_fh_.op != opcode::cont) + { + rd_size_ = rd_fh_.len; + rd_opcode_ = rd_fh_.op; + } + else + { + if(rd_size_ > (std::numeric_limits< + std::uint64_t>::max)() - rd_fh_.len) + { + code = close_code::too_big; + return; + } + rd_size_ += rd_fh_.len; + } + if(rd_msg_max_ && rd_size_ > rd_msg_max_) + { + code = close_code::too_big; + return; + } + rd_need_ = rd_fh_.len; + rd_cont_ = ! rd_fh_.fin; + } + code = close_code::none; +} + +template +void +stream_base:: +wr_prepare(bool compress) +{ + wr_.autofrag = wr_autofrag_; + wr_.compress = compress; + if(compress || wr_.autofrag || + role_ == detail::role_type::client) + { + if(! wr_.buf || wr_.size != wr_buf_size_) + { + wr_.size = wr_buf_size_; + wr_.buf.reset(new std::uint8_t[wr_.size]); + } + } + else + { + wr_.size = wr_buf_size_; + wr_.buf.reset(); + } +} + +template +void +stream_base:: +write_close(DynamicBuffer& db, close_reason const& cr) +{ + using namespace boost::endian; + frame_header fh; + fh.op = opcode::close; + fh.fin = true; + fh.rsv1 = false; + fh.rsv2 = false; + fh.rsv3 = false; + fh.len = cr.code == close_code::none ? + 0 : 2 + cr.reason.size(); + fh.mask = role_ == detail::role_type::client; + if(fh.mask) + fh.key = maskgen_(); + detail::write(db, fh); + if(cr.code != close_code::none) + { + detail::prepared_key_type key; + if(fh.mask) + detail::prepare_key(key, fh.key); + { + std::uint8_t b[2]; + ::new(&b[0]) big_uint16_buf_t{ + (std::uint16_t)cr.code}; + auto d = db.prepare(2); + boost::asio::buffer_copy(d, + boost::asio::buffer(b)); + if(fh.mask) + detail::mask_inplace(d, key); + db.commit(2); + } + if(! cr.reason.empty()) + { + auto d = db.prepare(cr.reason.size()); + boost::asio::buffer_copy(d, + boost::asio::const_buffer( + cr.reason.data(), cr.reason.size())); + if(fh.mask) + detail::mask_inplace(d, key); + db.commit(cr.reason.size()); + } + } +} + +template +void +stream_base:: +write_ping( + DynamicBuffer& db, opcode op, ping_data const& data) +{ + frame_header fh; + fh.op = op; + fh.fin = true; + fh.rsv1 = false; + fh.rsv2 = false; + fh.rsv3 = false; + fh.len = data.size(); + fh.mask = role_ == role_type::client; + if(fh.mask) + fh.key = maskgen_(); + detail::write(db, fh); + if(data.empty()) + return; + detail::prepared_key_type key; + if(fh.mask) + detail::prepare_key(key, fh.key); + auto d = db.prepare(data.size()); + boost::asio::buffer_copy(d, + boost::asio::const_buffers_1( + data.data(), data.size())); + if(fh.mask) + detail::mask_inplace(d, key); + db.commit(data.size()); +} + } // detail } // websocket } // beast diff --git a/include/beast/websocket/detail/utf8_checker.hpp b/include/beast/websocket/detail/utf8_checker.hpp index 6960819dd..be4619ba7 100644 --- a/include/beast/websocket/detail/utf8_checker.hpp +++ b/include/beast/websocket/detail/utf8_checker.hpp @@ -9,18 +9,19 @@ #define BEAST_WEBSOCKET_DETAIL_UTF8_CHECKER_HPP #include +#include +#include +#include #include -#include // DEPRECATED namespace beast { namespace websocket { namespace detail { -// Code adapted from -// http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ -/* - Copyright (c) 2008-2009 Bjoern Hoehrmann +/* This is a modified work. + Original version and license: + https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c 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 @@ -39,100 +40,97 @@ namespace detail { 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. * + + Additional changes: + Optimized for predominantly 7-bit content, 2016 + https://github.com/uWebSockets/uWebSockets/blob/755bd362649c06abff102f18e273c5792c51c1a0/src/WebSocketProtocol.h#L198 + Copyright (c) 2016 Alex Hultman and contributors + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgement in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/** A UTF8 validator. + + This validator can be used to check if a buffer containing UTF8 text is + valid. The write function may be called incrementally with segmented UTF8 + sequences. The finish function determines if all processed text is valid. */ template class utf8_checker_t { - // Table for the UTF8 decode state machine - using lut_type = std::uint8_t[400]; - static - lut_type const& - lut() - { - // 400 elements - static std::uint8_t constexpr tab[] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 00..1f - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 20..3f - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 40..5f - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 60..7f - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df - 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef - 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff - 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2 - 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4 - 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6 - 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1 // s7..s8 - }; - return tab; - } - - std::uint32_t state_ = 0; - std::uint32_t codepoint_ = 0; + std::size_t need_ = 0; + std::uint8_t* p_ = have_; + std::uint8_t have_[4]; public: + /** Prepare to process text as valid utf8 + */ void reset(); - // Returns `true` on success - bool - write(void const* buffer, std::size_t size); - - // Returns `true` on success - template - bool - write(BufferSequence const& bs); - - // Returns `true` on success + /** Check that all processed text is valid utf8 + */ bool finish(); + + /** Check if text is valid UTF8 + + @return `true` if the text is valid utf8 or false otherwise. + */ + bool + write(std::uint8_t const* in, std::size_t size); + + /** Check if text is valid UTF8 + + @return `true` if the text is valid utf8 or false otherwise. + */ + template + bool + write(ConstBufferSequence const& bs); }; template void utf8_checker_t<_>::reset() { - state_ = 0; - codepoint_ = 0; + need_ = 0; + p_ = have_; } template bool -utf8_checker_t<_>::write(void const* buffer, std::size_t size) +utf8_checker_t<_>::finish() { - auto p = static_cast(buffer); - auto plut = &lut()[0]; - while(size) - { - auto const byte = *p; - auto const type = plut[byte]; - if(state_) - codepoint_ = (byte & 0x3fu) | (codepoint_ << 6); - else - codepoint_ = (0xff >> type) & byte; - state_ = plut[256 + state_ * 16 + type]; - if(state_ == 1) - { - reset(); - return false; - } - ++p; - --size; - } - return true; + auto const success = need_ == 0; + reset(); + return success; } template -template +template bool -utf8_checker_t<_>::write(BufferSequence const& bs) +utf8_checker_t<_>::write(ConstBufferSequence const& bs) { + static_assert(is_ConstBufferSequence::value, + "ConstBufferSequence requirements not met"); using boost::asio::buffer_cast; using boost::asio::buffer_size; for(auto const& b : bs) - if(! write(buffer_cast(b), + if(! write(buffer_cast(b), buffer_size(b))) return false; return true; @@ -140,11 +138,164 @@ utf8_checker_t<_>::write(BufferSequence const& bs) template bool -utf8_checker_t<_>::finish() +utf8_checker_t<_>::write(std::uint8_t const* in, std::size_t size) { - auto const success = state_ == 0; - reset(); - return success; + auto const valid = + [](std::uint8_t const*& in) + { + if (in[0] < 128) + { + ++in; + return true; + } + if ((in[0] & 0x60) == 0x40) + { + if ((in[1] & 0xc0) != 0x80) + return false; + in += 2; + return true; + } + if ((in[0] & 0xf0) == 0xe0) + { + if ((in[1] & 0xc0) != 0x80 || + (in[2] & 0xc0) != 0x80 || + (in[0] == 224 && in[1] < 160) || + (in[0] == 237 && in[1] > 159)) + return false; + in += 3; + return true; + } + if ((in[0] & 0xf8) == 0xf0) + { + if (in[0] > 244 || + (in[1] & 0xc0) != 0x80 || + (in[2] & 0xc0) != 0x80 || + (in[3] & 0xc0) != 0x80 || + (in[0] == 240 && in[1] < 144) || + (in[0] == 244 && in[1] > 143)) + return false; + in += 4; + return true; + } + return false; + }; + auto const valid_have = + [&]() + { + if ((have_[0] & 0x60) == 0x40) + return have_[0] <= 223; + if ((have_[0] & 0xf0) == 0xe0) + { + if (p_ - have_ > 1 && + ((have_[1] & 0xc0) != 0x80 || + (have_[0] == 224 && have_[1] < 160) || + (have_[0] == 237 && have_[1] > 159))) + return false; + return true; + } + if ((have_[0] & 0xf8) == 0xf0) + { + auto const size = p_ - have_; + if (size > 2 && (have_[2] & 0xc0) != 0x80) + return false; + if (size > 1 && + ((have_[1] & 0xc0) != 0x80 || + (have_[0] == 240 && have_[1] < 144) || + (have_[0] == 244 && have_[1] > 143))) + return false; + } + return true; + }; + auto const needed = + [](std::uint8_t const in) + { + if (in < 128) + return 1; + if (in < 194) + return 0; + if (in < 224) + return 2; + if (in < 240) + return 3; + if (in < 245) + return 4; + return 0; + }; + + auto const end = in + size; + if (need_ > 0) + { + auto n = (std::min)(size, need_); + size -= n; + need_ -= n; + while(n--) + *p_++ = *in++; + if(need_ > 0) + { + BOOST_ASSERT(in == end); + return valid_have(); + } + std::uint8_t const* p = &have_[0]; + if (! valid(p)) + return false; + p_ = have_; + } + + auto last = in + size - 7; + while(in < last) + { +#if BEAST_WEBSOCKET_NO_UNALIGNED_READ + auto constexpr align = sizeof(std::size_t) - 1; + auto constexpr mask = static_cast< + std::size_t>(0x8080808080808080 & + ~std::size_t{0}); + if( + ((reinterpret_cast< + std::uintptr_t>(in) & align) == 0) && + (*reinterpret_cast< + std::size_t const*>(in) & mask) == 0) + in += sizeof(std::size_t); + else if(! valid(in)) + return false; +#else + auto constexpr mask = static_cast< + std::size_t>(0x8080808080808080 & + ~std::size_t{0}); + if( + (*reinterpret_cast< + std::size_t const*>(in) & mask) == 0) + in += sizeof(std::size_t); + else if(! valid(in)) + return false; +#endif + } + last += 4; + while(in < last) + if(! valid(in)) + return false; + + for(;;) + { + auto n = end - in; + if(! n) + break; + auto const need = needed(*in); + if (need == 0) + return false; + if(need <= n) + { + if(! valid(in)) + return false; + } + else + { + need_ = need - n; + while(n--) + *p_++ = *in++; + return valid_have(); + } + } + return true; } using utf8_checker = utf8_checker_t<>; @@ -154,7 +305,7 @@ bool check_utf8(char const* p, std::size_t n) { utf8_checker c; - if(! c.write(p, n)) + if(! c.write(reinterpret_cast(p), n)) return false; return c.finish(); } diff --git a/include/beast/websocket/error.hpp b/include/beast/websocket/error.hpp index c86307cb4..12e1306de 100644 --- a/include/beast/websocket/error.hpp +++ b/include/beast/websocket/error.hpp @@ -13,13 +13,11 @@ namespace beast { namespace websocket { -/// Error codes returned from @ref stream operations. +/// Error codes returned from @ref beast::websocket::stream operations. enum class error { - success = 0, - /// Both sides performed a WebSocket close - closed, + closed = 1, /// WebSocket connection failed, protocol violation failed, @@ -52,11 +50,6 @@ enum class error general }; -#if ! GENERATING_DOCS -error_code -make_error_code(error e); -#endif - } // websocket } // beast diff --git a/include/beast/websocket/impl/accept.ipp b/include/beast/websocket/impl/accept.ipp new file mode 100644 index 000000000..c33852c87 --- /dev/null +++ b/include/beast/websocket/impl/accept.ipp @@ -0,0 +1,423 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_WEBSOCKET_IMPL_ACCEPT_IPP +#define BEAST_WEBSOCKET_IMPL_ACCEPT_IPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace websocket { + +//------------------------------------------------------------------------------ + +// Respond to an upgrade HTTP request +template +template +class stream::response_op +{ + struct data + { + bool cont; + stream& ws; + http::response resp; + error_code final_ec; + int state = 0; + + template + data(Handler&, stream& ws_, + http::request const& req, + bool cont_) + : cont(cont_) + , ws(ws_) + , resp(ws_.build_response(req)) + { + // can't call stream::reset() here + // otherwise accept_op will malfunction + // + if(resp.status != 101) + final_ec = error::handshake_failed; + } + }; + + handler_ptr d_; + +public: + response_op(response_op&&) = default; + response_op(response_op const&) = default; + + template + response_op(DeducedHandler&& h, + stream& ws, Args&&... args) + : d_(make_handler_ptr( + std::forward(h), ws, + std::forward(args)...)) + { + (*this)(error_code{}, false); + } + + void operator()( + error_code ec, bool again = true); + + friend + void* asio_handler_allocate( + std::size_t size, response_op* op) + { + return beast_asio_helpers:: + allocate(size, op->d_.handler()); + } + + friend + void asio_handler_deallocate( + void* p, std::size_t size, response_op* op) + { + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); + } + + friend + bool asio_handler_is_continuation(response_op* op) + { + return op->d_->cont; + } + + template + friend + void asio_handler_invoke(Function&& f, response_op* op) + { + return beast_asio_helpers:: + invoke(f, op->d_.handler()); + } +}; + +template +template +void +stream::response_op:: +operator()(error_code ec, bool again) +{ + auto& d = *d_; + d.cont = d.cont || again; + while(! ec && d.state != 99) + { + switch(d.state) + { + case 0: + // send response + d.state = 1; + http::async_write(d.ws.next_layer(), + d.resp, std::move(*this)); + return; + + // sent response + case 1: + d.state = 99; + ec = d.final_ec; + if(! ec) + d.ws.open(detail::role_type::server); + break; + } + } + d_.invoke(ec); +} + +//------------------------------------------------------------------------------ + +// read and respond to an upgrade request +// +template +template +class stream::accept_op +{ + struct data + { + bool cont; + stream& ws; + http::request req; + int state = 0; + + template + data(Handler& handler, stream& ws_, + Buffers const& buffers) + : cont(beast_asio_helpers:: + is_continuation(handler)) + , ws(ws_) + { + using boost::asio::buffer_copy; + using boost::asio::buffer_size; + ws.reset(); + ws.stream_.buffer().commit(buffer_copy( + ws.stream_.buffer().prepare( + buffer_size(buffers)), buffers)); + } + }; + + handler_ptr d_; + +public: + accept_op(accept_op&&) = default; + accept_op(accept_op const&) = default; + + template + accept_op(DeducedHandler&& h, + stream& ws, Args&&... args) + : d_(make_handler_ptr( + std::forward(h), ws, + std::forward(args)...)) + { + (*this)(error_code{}, 0, false); + } + + void operator()(error_code const& ec) + { + (*this)(ec, 0); + } + + void operator()(error_code const& ec, + std::size_t bytes_transferred, bool again = true); + + friend + void* asio_handler_allocate( + std::size_t size, accept_op* op) + { + return beast_asio_helpers:: + allocate(size, op->d_.handler()); + } + + friend + void asio_handler_deallocate( + void* p, std::size_t size, accept_op* op) + { + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); + } + + friend + bool asio_handler_is_continuation(accept_op* op) + { + return op->d_->cont; + } + + template + friend + void asio_handler_invoke(Function&& f, accept_op* op) + { + return beast_asio_helpers:: + invoke(f, op->d_.handler()); + } +}; + +template +template +void +stream::accept_op:: +operator()(error_code const& ec, + std::size_t bytes_transferred, bool again) +{ + beast::detail::ignore_unused(bytes_transferred); + auto& d = *d_; + d.cont = d.cont || again; + while(! ec && d.state != 99) + { + switch(d.state) + { + case 0: + // read message + d.state = 1; + http::async_read(d.ws.next_layer(), + d.ws.stream_.buffer(), d.req, + std::move(*this)); + return; + + // got message + case 1: + { + // respond to request + auto& ws = d.ws; + auto req = std::move(d.req); + response_op{ + d_.release_handler(), ws, req, true}; + return; + } + } + } + d_.invoke(ec); +} + +template +template +typename async_completion< + AcceptHandler, void(error_code)>::result_type +stream:: +async_accept(AcceptHandler&& handler) +{ + static_assert(is_AsyncStream::value, + "AsyncStream requirements requirements not met"); + return async_accept(boost::asio::null_buffers{}, + std::forward(handler)); +} + +template +template +typename async_completion< + AcceptHandler, void(error_code)>::result_type +stream:: +async_accept(ConstBufferSequence const& bs, AcceptHandler&& handler) +{ + static_assert(is_AsyncStream::value, + "AsyncStream requirements requirements not met"); + static_assert(beast::is_ConstBufferSequence< + ConstBufferSequence>::value, + "ConstBufferSequence requirements not met"); + beast::async_completion< + AcceptHandler, void(error_code) + > completion(handler); + accept_op{ + completion.handler, *this, bs}; + return completion.result.get(); +} + +template +template +typename async_completion< + AcceptHandler, void(error_code)>::result_type +stream:: +async_accept(http::request const& req, + AcceptHandler&& handler) +{ + static_assert(is_AsyncStream::value, + "AsyncStream requirements requirements not met"); + beast::async_completion< + AcceptHandler, void(error_code) + > completion(handler); + reset(); + response_op{ + completion.handler, *this, req, + beast_asio_helpers:: + is_continuation(completion.handler)}; + return completion.result.get(); +} + +template +void +stream:: +accept() +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + error_code ec; + accept(boost::asio::null_buffers{}, ec); + if(ec) + throw system_error{ec}; +} + +template +void +stream:: +accept(error_code& ec) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + accept(boost::asio::null_buffers{}, ec); +} + +template +template +void +stream:: +accept(ConstBufferSequence const& buffers) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + static_assert(is_ConstBufferSequence< + ConstBufferSequence>::value, + "ConstBufferSequence requirements not met"); + error_code ec; + accept(buffers, ec); + if(ec) + throw system_error{ec}; +} + +template +template +void +stream:: +accept(ConstBufferSequence const& buffers, error_code& ec) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + static_assert(beast::is_ConstBufferSequence< + ConstBufferSequence>::value, + "ConstBufferSequence requirements not met"); + using boost::asio::buffer_copy; + using boost::asio::buffer_size; + reset(); + stream_.buffer().commit(buffer_copy( + stream_.buffer().prepare( + buffer_size(buffers)), buffers)); + http::request m; + http::read(next_layer(), stream_.buffer(), m, ec); + if(ec) + return; + accept(m, ec); +} + +template +template +void +stream:: +accept(http::request const& request) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + error_code ec; + accept(request, ec); + if(ec) + throw system_error{ec}; +} + +template +template +void +stream:: +accept(http::request const& req, + error_code& ec) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + reset(); + auto const res = build_response(req); + http::write(stream_, res, ec); + if(ec) + return; + if(res.status != 101) + { + ec = error::handshake_failed; + // VFALCO TODO Respect keep alive setting, perform + // teardown if Connection: close. + return; + } + open(detail::role_type::server); +} + +//------------------------------------------------------------------------------ + +} // websocket +} // beast + +#endif diff --git a/include/beast/websocket/impl/accept_op.ipp b/include/beast/websocket/impl/accept_op.ipp deleted file mode 100644 index 38443eb4a..000000000 --- a/include/beast/websocket/impl/accept_op.ipp +++ /dev/null @@ -1,154 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_WEBSOCKET_IMPL_ACCEPT_OP_HPP -#define BEAST_WEBSOCKET_IMPL_ACCEPT_OP_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace beast { -namespace websocket { - -// read and respond to an upgrade request -// -template -template -class stream::accept_op -{ - using alloc_type = - handler_alloc; - - struct data - { - stream& ws; - http::request_v1 req; - Handler h; - bool cont; - int state = 0; - - template - data(DeducedHandler&& h_, stream& ws_, - Buffers const& buffers) - : ws(ws_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) - { - using boost::asio::buffer_copy; - using boost::asio::buffer_size; - ws.reset(); - ws.stream_.buffer().commit(buffer_copy( - ws.stream_.buffer().prepare( - buffer_size(buffers)), buffers)); - } - }; - - std::shared_ptr d_; - -public: - accept_op(accept_op&&) = default; - accept_op(accept_op const&) = default; - - template - accept_op(DeducedHandler&& h, - stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, - std::forward(h), ws, - std::forward(args)...)) - { - (*this)(error_code{}, 0, false); - } - - void operator()(error_code const& ec) - { - (*this)(ec, 0); - } - - void operator()(error_code const& ec, - std::size_t bytes_transferred, bool again = true); - - friend - void* asio_handler_allocate( - std::size_t size, accept_op* op) - { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); - } - - friend - void asio_handler_deallocate( - void* p, std::size_t size, accept_op* op) - { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); - } - - friend - bool asio_handler_is_continuation(accept_op* op) - { - return op->d_->cont; - } - - template - friend - void asio_handler_invoke(Function&& f, accept_op* op) - { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); - } -}; - -template -template -void -stream::accept_op:: -operator()(error_code const& ec, - std::size_t bytes_transferred, bool again) -{ - auto& d = *d_; - d.cont = d.cont || again; - while(! ec && d.state != 99) - { - switch(d.state) - { - case 0: - // read message - d.state = 1; - http::async_read(d.ws.next_layer(), - d.ws.stream_.buffer(), d.req, - std::move(*this)); - return; - - // got message - case 1: - // respond to request -#if 1 - // VFALCO I have no idea why passing std::move(*this) crashes - d.state = 99; - d.ws.async_accept(d.req, *this); -#else - response_op{ - std::move(d.h), d.ws, d.req, true}; -#endif - return; - } - } - d.h(ec); -} - -} // websocket -} // beast - -#endif diff --git a/include/beast/websocket/impl/close_op.ipp b/include/beast/websocket/impl/close.ipp similarity index 63% rename from include/beast/websocket/impl/close_op.ipp rename to include/beast/websocket/impl/close.ipp index 4884a2a17..7e929b588 100644 --- a/include/beast/websocket/impl/close_op.ipp +++ b/include/beast/websocket/impl/close.ipp @@ -5,50 +5,49 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_WEBSOCKET_IMPL_CLOSE_OP_HPP -#define BEAST_WEBSOCKET_IMPL_CLOSE_OP_HPP +#ifndef BEAST_WEBSOCKET_IMPL_CLOSE_IPP +#define BEAST_WEBSOCKET_IMPL_CLOSE_IPP -#include +#include +#include #include +#include #include namespace beast { namespace websocket { +//------------------------------------------------------------------------------ + // send the close message and wait for the response // template template class stream::close_op { - using alloc_type = handler_alloc; - using fb_type = detail::frame_streambuf; struct data : op { + bool cont; stream& ws; close_reason cr; - Handler h; fb_type fb; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + data(Handler& handler, stream& ws_, close_reason const& cr_) - : ws(ws_) + : cont(beast_asio_helpers:: + is_continuation(handler)) + , ws(ws_) , cr(cr_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { ws.template write_close< static_streambuf>(fb, cr); } }; - std::shared_ptr d_; + handler_ptr d_; public: close_op(close_op&&) = default; @@ -57,7 +56,7 @@ public: template close_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -79,16 +78,16 @@ public: void* asio_handler_allocate( std::size_t size, close_op* op) { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + return beast_asio_helpers:: + allocate(size, op->d_.handler()); } friend void asio_handler_deallocate( void* p, std::size_t size, close_op* op) { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); } friend @@ -101,8 +100,8 @@ public: friend void asio_handler_invoke(Function&& f, close_op* op) { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + return beast_asio_helpers:: + invoke(f, op->d_.handler()); } }; @@ -155,7 +154,7 @@ operator()(error_code ec, bool again) // send close frame d.state = 99; d.ws.wr_close_ = true; - assert(! d.ws.wr_block_); + BOOST_ASSERT(! d.ws.wr_block_); d.ws.wr_block_ = &d; boost::asio::async_write(d.ws.stream_, d.fb.data(), std::move(*this)); @@ -185,9 +184,56 @@ upcall: if(d.ws.wr_block_ == &d) d.ws.wr_block_ = nullptr; d.ws.rd_op_.maybe_invoke(); - d.h(ec); + d_.invoke(ec); } +template +template +typename async_completion< + CloseHandler, void(error_code)>::result_type +stream:: +async_close(close_reason const& cr, CloseHandler&& handler) +{ + static_assert(is_AsyncStream::value, + "AsyncStream requirements not met"); + beast::async_completion< + CloseHandler, void(error_code) + > completion(handler); + close_op{ + completion.handler, *this, cr}; + return completion.result.get(); +} + +template +void +stream:: +close(close_reason const& cr) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + error_code ec; + close(cr, ec); + if(ec) + throw system_error{ec}; +} + +template +void +stream:: +close(close_reason const& cr, error_code& ec) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + BOOST_ASSERT(! wr_close_); + wr_close_ = true; + detail::frame_streambuf fb; + write_close(fb, cr); + boost::asio::write(stream_, fb.data(), ec); + failed_ = ec != 0; +} + +//------------------------------------------------------------------------------ + } // websocket } // beast diff --git a/include/beast/websocket/impl/error.ipp b/include/beast/websocket/impl/error.ipp index b4c291022..19c497a4d 100644 --- a/include/beast/websocket/impl/error.ipp +++ b/include/beast/websocket/impl/error.ipp @@ -5,20 +5,93 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_WEBSOCKET_IMPL_ERROR_IPP_HPP -#define BEAST_WEBSOCKET_IMPL_ERROR_IPP_HPP +#ifndef BEAST_WEBSOCKET_IMPL_ERROR_IPP +#define BEAST_WEBSOCKET_IMPL_ERROR_IPP -#include +namespace boost { +namespace system { +template<> +struct is_error_code_enum +{ + static bool const value = true; +}; +} // system +} // boost namespace beast { namespace websocket { +namespace detail { + +class websocket_error_category : public error_category +{ +public: + const char* + name() const noexcept override + { + return "websocket"; + } + + std::string + message(int ev) const override + { + switch(static_cast(ev)) + { + case error::closed: return "WebSocket connection closed normally"; + case error::failed: return "WebSocket connection failed due to a protocol violation"; + case error::handshake_failed: return "WebSocket Upgrade handshake failed"; + case error::keep_alive: return "WebSocket Upgrade handshake failed but connection is still open"; + + case error::response_malformed: return "malformed HTTP response"; + case error::response_failed: return "upgrade request failed"; + case error::response_denied: return "upgrade request denied"; + case error::request_malformed: return "malformed HTTP request"; + case error::request_invalid: return "upgrade request invalid"; + case error::request_denied: return "upgrade request denied"; + default: + return "websocket error"; + } + } + + error_condition + default_error_condition(int ev) const noexcept override + { + return error_condition(ev, *this); + } + + bool + equivalent(int ev, + error_condition const& condition + ) const noexcept override + { + return condition.value() == ev && + &condition.category() == this; + } + + bool + equivalent(error_code const& error, int ev) const noexcept override + { + return error.value() == ev && + &error.category() == this; + } +}; + +inline +error_category const& +get_error_category() +{ + static detail::websocket_error_category const cat{}; + return cat; +} + +} // detail inline error_code make_error_code(error e) { return error_code( - static_cast(e), detail::get_error_category()); + static_cast::type>(e), + detail::get_error_category()); } } // websocket diff --git a/include/beast/websocket/impl/handshake_op.ipp b/include/beast/websocket/impl/handshake.ipp similarity index 52% rename from include/beast/websocket/impl/handshake_op.ipp rename to include/beast/websocket/impl/handshake.ipp index 8443fd9ad..acc9cd2d4 100644 --- a/include/beast/websocket/impl/handshake_op.ipp +++ b/include/beast/websocket/impl/handshake.ipp @@ -5,54 +5,52 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_WEBSOCKET_IMPL_HANDSHAKE_OP_HPP -#define BEAST_WEBSOCKET_IMPL_HANDSHAKE_OP_HPP +#ifndef BEAST_WEBSOCKET_IMPL_HANDSHAKE_IPP +#define BEAST_WEBSOCKET_IMPL_HANDSHAKE_IPP #include -#include +#include #include #include -#include -#include +#include +#include +#include +#include #include namespace beast { namespace websocket { +//------------------------------------------------------------------------------ + // send the upgrade request and process the response // template template class stream::handshake_op { - using alloc_type = - handler_alloc; - struct data { - stream& ws; - Handler h; - std::string key; - http::request_v1 req; - http::response_v1 resp; bool cont; + stream& ws; + std::string key; + http::request req; + http::response resp; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + data(Handler& handler, stream& ws_, boost::string_ref const& host, boost::string_ref const& resource) - : ws(ws_) - , h(std::forward(h_)) + : cont(beast_asio_helpers:: + is_continuation(handler)) + , ws(ws_) , req(ws.build_request(host, resource, key)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { ws.reset(); } }; - std::shared_ptr d_; + handler_ptr d_; public: handshake_op(handshake_op&&) = default; @@ -61,7 +59,7 @@ public: template handshake_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -75,16 +73,16 @@ public: void* asio_handler_allocate( std::size_t size, handshake_op* op) { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + return beast_asio_helpers:: + allocate(size, op->d_.handler()); } friend void asio_handler_deallocate( void* p, std::size_t size, handshake_op* op) { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); } friend @@ -97,8 +95,8 @@ public: friend void asio_handler_invoke(Function&& f, handshake_op* op) { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + return beast_asio_helpers:: + invoke(f, op->d_.handler()); } }; @@ -144,9 +142,64 @@ operator()(error_code ec, bool again) } } } - d.h(ec); + d_.invoke(ec); } +template +template +typename async_completion< + HandshakeHandler, void(error_code)>::result_type +stream:: +async_handshake(boost::string_ref const& host, + boost::string_ref const& resource, HandshakeHandler&& handler) +{ + static_assert(is_AsyncStream::value, + "AsyncStream requirements not met"); + beast::async_completion< + HandshakeHandler, void(error_code) + > completion(handler); + handshake_op{ + completion.handler, *this, host, resource}; + return completion.result.get(); +} + +template +void +stream:: +handshake(boost::string_ref const& host, + boost::string_ref const& resource) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + error_code ec; + handshake(host, resource, ec); + if(ec) + throw system_error{ec}; +} + +template +void +stream:: +handshake(boost::string_ref const& host, + boost::string_ref const& resource, error_code& ec) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + reset(); + std::string key; + http::write(stream_, + build_request(host, resource, key), ec); + if(ec) + return; + http::response res; + http::read(next_layer(), stream_.buffer(), res, ec); + if(ec) + return; + do_response(res, key, ec); +} + +//------------------------------------------------------------------------------ + } // websocket } // beast diff --git a/include/beast/websocket/impl/ping_op.ipp b/include/beast/websocket/impl/ping.ipp similarity index 54% rename from include/beast/websocket/impl/ping_op.ipp rename to include/beast/websocket/impl/ping.ipp index 8fc9936d8..d9e7ba51f 100644 --- a/include/beast/websocket/impl/ping_op.ipp +++ b/include/beast/websocket/impl/ping.ipp @@ -5,50 +5,48 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_WEBSOCKET_IMPL_PING_OP_HPP -#define BEAST_WEBSOCKET_IMPL_PING_OP_HPP +#ifndef BEAST_WEBSOCKET_IMPL_PING_IPP +#define BEAST_WEBSOCKET_IMPL_PING_IPP #include -#include +#include +#include +#include #include #include namespace beast { namespace websocket { +//------------------------------------------------------------------------------ + // write a ping frame // template template class stream::ping_op { - using alloc_type = - handler_alloc; - struct data : op { - stream& ws; - Handler h; - detail::frame_streambuf fb; bool cont; + stream& ws; + detail::frame_streambuf fb; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, - ping_data const& payload) - : ws(ws_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) + data(Handler& handler, stream& ws_, + opcode op_, ping_data const& payload) + : cont(beast_asio_helpers:: + is_continuation(handler)) + , ws(ws_) { using boost::asio::buffer; using boost::asio::buffer_copy; - ws.template write_ping( - fb, opcode::ping, payload); + ws.template write_ping< + static_streambuf>(fb, op_, payload); } }; - std::shared_ptr d_; + handler_ptr d_; public: ping_op(ping_op&&) = default; @@ -57,7 +55,7 @@ public: template ping_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::make_shared( + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -77,16 +75,16 @@ public: void* asio_handler_allocate( std::size_t size, ping_op* op) { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + return beast_asio_helpers:: + allocate(size, op->d_.handler()); } friend void asio_handler_deallocate( void* p, std::size_t size, ping_op* op) { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); } friend @@ -99,8 +97,8 @@ public: friend void asio_handler_invoke(Function&& f, ping_op* op) { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + return beast_asio_helpers:: + invoke(f, op->d_.handler()); } }; @@ -154,7 +152,7 @@ operator()(error_code ec, bool again) case 1: // send ping frame d.state = 99; - assert(! d.ws.wr_block_); + BOOST_ASSERT(! d.ws.wr_block_); d.ws.wr_block_ = &d; boost::asio::async_write(d.ws.stream_, d.fb.data(), std::move(*this)); @@ -184,9 +182,91 @@ upcall: if(d.ws.wr_block_ == &d) d.ws.wr_block_ = nullptr; d.ws.rd_op_.maybe_invoke(); - d.h(ec); + d_.invoke(ec); } +template +template +typename async_completion< + WriteHandler, void(error_code)>::result_type +stream:: +async_ping(ping_data const& payload, WriteHandler&& handler) +{ + static_assert(is_AsyncStream::value, + "AsyncStream requirements requirements not met"); + beast::async_completion< + WriteHandler, void(error_code) + > completion(handler); + ping_op{ + completion.handler, *this, + opcode::ping, payload}; + return completion.result.get(); +} + +template +template +typename async_completion< + WriteHandler, void(error_code)>::result_type +stream:: +async_pong(ping_data const& payload, WriteHandler&& handler) +{ + static_assert(is_AsyncStream::value, + "AsyncStream requirements requirements not met"); + beast::async_completion< + WriteHandler, void(error_code) + > completion(handler); + ping_op{ + completion.handler, *this, + opcode::pong, payload}; + return completion.result.get(); +} + +template +void +stream:: +ping(ping_data const& payload) +{ + error_code ec; + ping(payload, ec); + if(ec) + throw system_error{ec}; +} + +template +void +stream:: +ping(ping_data const& payload, error_code& ec) +{ + detail::frame_streambuf db; + write_ping( + db, opcode::ping, payload); + boost::asio::write(stream_, db.data(), ec); +} + +template +void +stream:: +pong(ping_data const& payload) +{ + error_code ec; + pong(payload, ec); + if(ec) + throw system_error{ec}; +} + +template +void +stream:: +pong(ping_data const& payload, error_code& ec) +{ + detail::frame_streambuf db; + write_ping( + db, opcode::pong, payload); + boost::asio::write(stream_, db.data(), ec); +} + +//------------------------------------------------------------------------------ + } // websocket } // beast diff --git a/include/beast/websocket/impl/read_frame_op.ipp b/include/beast/websocket/impl/read.ipp similarity index 56% rename from include/beast/websocket/impl/read_frame_op.ipp rename to include/beast/websocket/impl/read.ipp index 0ba001764..d4469d7b3 100644 --- a/include/beast/websocket/impl/read_frame_op.ipp +++ b/include/beast/websocket/impl/read.ipp @@ -5,20 +5,26 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#ifndef BEAST_WEBSOCKET_IMPL_READ_FRAME_OP_HPP -#define BEAST_WEBSOCKET_IMPL_READ_FRAME_OP_HPP +#ifndef BEAST_WEBSOCKET_IMPL_READ_IPP +#define BEAST_WEBSOCKET_IMPL_READ_IPP #include -#include +#include +#include +#include #include #include +#include +#include +#include #include -#include #include namespace beast { namespace websocket { +//------------------------------------------------------------------------------ + // Reads a single message frame, // processes any received control frames. // @@ -26,9 +32,6 @@ template template class stream::read_frame_op { - using alloc_type = - handler_alloc; - using fb_type = detail::frame_streambuf; @@ -40,30 +43,27 @@ class stream::read_frame_op struct data : op { + bool cont; stream& ws; frame_info& fi; DynamicBuffer& db; - Handler h; fb_type fb; boost::optional dmb; boost::optional fmb; - bool cont; int state = 0; - template - data(DeducedHandler&& h_, stream& ws_, + data(Handler& handler, stream& ws_, frame_info& fi_, DynamicBuffer& sb_) - : ws(ws_) + : cont(beast_asio_helpers:: + is_continuation(handler)) + , ws(ws_) , fi(fi_) , db(sb_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) { } }; - std::shared_ptr d_; + handler_ptr d_; public: read_frame_op(read_frame_op&&) = default; @@ -72,7 +72,7 @@ public: template read_frame_op(DeducedHandler&& h, stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, + : d_(make_handler_ptr( std::forward(h), ws, std::forward(args)...)) { @@ -99,16 +99,16 @@ public: void* asio_handler_allocate( std::size_t size, read_frame_op* op) { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + return beast_asio_helpers:: + allocate(size, op->d_.handler()); } friend void asio_handler_deallocate( void* p, std::size_t size, read_frame_op* op) { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); } friend @@ -121,8 +121,8 @@ public: friend void asio_handler_invoke(Function&& f, read_frame_op* op) { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + return beast_asio_helpers:: + invoke(f, op->d_.handler()); } }; @@ -144,6 +144,7 @@ void stream::read_frame_op:: operator()(error_code ec,std::size_t bytes_transferred, bool again) { + using beast::detail::clamp; enum { do_start = 0, @@ -156,6 +157,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again) do_pong = 11, do_close_resume = 13, do_close = 15, + do_teardown = 16, do_fail = 18, do_call_handler = 99 @@ -187,8 +189,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again) case do_read_payload: d.state = do_read_payload + 1; - d.dmb = d.db.prepare( - detail::clamp(d.ws.rd_need_)); + d.dmb = d.db.prepare(clamp(d.ws.rd_need_)); // receive payload data d.ws.stream_.async_read_some( *d.dmb, std::move(*this)); @@ -243,8 +244,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again) { d.fb.commit(bytes_transferred); code = close_code::none; - auto const n = detail::read_fh1( - d.ws.rd_fh_, d.fb, d.ws.role_, code); + auto const n = d.ws.read_fh1(d.fb, code); if(code != close_code::none) { // protocol error @@ -266,10 +266,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again) case do_read_fh + 2: d.fb.commit(bytes_transferred); code = close_code::none; - detail::read_fh2(d.ws.rd_fh_, - d.fb, d.ws.role_, code); - if(code == close_code::none) - d.ws.prepare_fh(code); + d.ws.read_fh2(d.fb, code); if(code != close_code::none) { // protocol error @@ -330,7 +327,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again) { // suspend d.state = do_pong_resume; - assert(d.ws.wr_block_ != &d); + BOOST_ASSERT(d.ws.wr_block_ != &d); d.ws.rd_op_.template emplace< read_frame_op>(std::move(*this)); return; @@ -349,7 +346,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again) d.state = do_read_fh; break; } - assert(d.ws.rd_fh_.op == opcode::close); + BOOST_ASSERT(d.ws.rd_fh_.op == opcode::close); { detail::read(d.ws.cr_, d.fb.data(), code); if(code != close_code::none) @@ -378,9 +375,8 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again) d.state = do_close; break; } - // call handler; - ec = error::closed; - goto upcall; + d.state = do_teardown; + break; } //------------------------------------------------------------------ @@ -413,7 +409,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again) } // send pong d.state = do_pong + 1; - assert(! d.ws.wr_block_); + BOOST_ASSERT(! d.ws.wr_block_); d.ws.wr_block_ = &d; boost::asio::async_write(d.ws.stream_, d.fb.data(), std::move(*this)); @@ -453,21 +449,23 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again) //------------------------------------------------------------------ case do_close: - d.state = do_close + 1; + d.state = do_teardown; d.ws.wr_close_ = true; - assert(! d.ws.wr_block_); + BOOST_ASSERT(! d.ws.wr_block_); d.ws.wr_block_ = &d; boost::asio::async_write(d.ws.stream_, d.fb.data(), std::move(*this)); return; - case do_close + 1: - d.state = do_close + 2; + //------------------------------------------------------------------ + + case do_teardown: + d.state = do_teardown + 1; websocket_helpers::call_async_teardown( d.ws.next_layer(), std::move(*this)); return; - case do_close + 2: + case do_teardown + 1: // call handler ec = error::closed; goto upcall; @@ -498,7 +496,7 @@ operator()(error_code ec,std::size_t bytes_transferred, bool again) // send close frame d.state = do_fail + 4; d.ws.wr_close_ = true; - assert(! d.ws.wr_block_); + BOOST_ASSERT(! d.ws.wr_block_); d.ws.wr_block_ = &d; boost::asio::async_write(d.ws.stream_, d.fb.data(), std::move(*this)); @@ -542,9 +540,365 @@ upcall: if(d.ws.wr_block_ == &d) d.ws.wr_block_ = nullptr; d.ws.wr_op_.maybe_invoke(); - d.h(ec); + d_.invoke(ec); } +template +template +typename async_completion< + ReadHandler, void(error_code)>::result_type +stream:: +async_read_frame(frame_info& fi, + DynamicBuffer& dynabuf, ReadHandler&& handler) +{ + static_assert(is_AsyncStream::value, + "AsyncStream requirements requirements not met"); + static_assert(beast::is_DynamicBuffer::value, + "DynamicBuffer requirements not met"); + beast::async_completion< + ReadHandler, void(error_code)> completion(handler); + read_frame_op{ + completion.handler, *this, fi, dynabuf}; + return completion.result.get(); +} + +template +template +void +stream:: +read_frame(frame_info& fi, DynamicBuffer& dynabuf) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + static_assert(beast::is_DynamicBuffer::value, + "DynamicBuffer requirements not met"); + error_code ec; + read_frame(fi, dynabuf, ec); + if(ec) + throw system_error{ec}; +} + +template +template +void +stream:: +read_frame(frame_info& fi, DynamicBuffer& dynabuf, error_code& ec) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + static_assert(beast::is_DynamicBuffer::value, + "DynamicBuffer requirements not met"); + using beast::detail::clamp; + close_code::value code{}; + for(;;) + { + if(rd_need_ == 0) + { + // read header + detail::frame_streambuf fb; + do_read_fh(fb, code, ec); + failed_ = ec != 0; + if(failed_) + return; + if(code != close_code::none) + break; + if(detail::is_control(rd_fh_.op)) + { + // read control payload + if(rd_fh_.len > 0) + { + auto const mb = fb.prepare( + static_cast(rd_fh_.len)); + fb.commit(boost::asio::read(stream_, mb, ec)); + failed_ = ec != 0; + if(failed_) + return; + if(rd_fh_.mask) + detail::mask_inplace(mb, rd_key_); + fb.commit(static_cast(rd_fh_.len)); + } + if(rd_fh_.op == opcode::ping) + { + ping_data data; + detail::read(data, fb.data()); + fb.reset(); + write_ping( + fb, opcode::pong, data); + boost::asio::write(stream_, fb.data(), ec); + failed_ = ec != 0; + if(failed_) + return; + continue; + } + else if(rd_fh_.op == opcode::pong) + { + ping_data payload; + detail::read(payload, fb.data()); + if(pong_cb_) + pong_cb_(payload); + continue; + } + BOOST_ASSERT(rd_fh_.op == opcode::close); + { + detail::read(cr_, fb.data(), code); + if(code != close_code::none) + break; + if(! wr_close_) + { + auto cr = cr_; + if(cr.code == close_code::none) + cr.code = close_code::normal; + cr.reason = ""; + fb.reset(); + wr_close_ = true; + write_close(fb, cr); + boost::asio::write(stream_, fb.data(), ec); + failed_ = ec != 0; + if(failed_) + return; + } + break; + } + } + if(rd_need_ == 0 && ! rd_fh_.fin) + { + // empty frame + continue; + } + } + // read payload + auto smb = dynabuf.prepare(clamp(rd_need_)); + auto const bytes_transferred = + stream_.read_some(smb, ec); + failed_ = ec != 0; + if(failed_) + return; + rd_need_ -= bytes_transferred; + auto const pb = prepare_buffers( + bytes_transferred, smb); + if(rd_fh_.mask) + detail::mask_inplace(pb, rd_key_); + if(rd_opcode_ == opcode::text) + { + if(! rd_utf8_check_.write(pb) || + (rd_need_ == 0 && rd_fh_.fin && + ! rd_utf8_check_.finish())) + { + code = close_code::bad_payload; + break; + } + } + dynabuf.commit(bytes_transferred); + fi.op = rd_opcode_; + fi.fin = rd_fh_.fin && rd_need_ == 0; + return; + } + if(code != close_code::none) + { + // Fail the connection (per rfc6455) + if(! wr_close_) + { + wr_close_ = true; + detail::frame_streambuf fb; + write_close(fb, code); + boost::asio::write(stream_, fb.data(), ec); + failed_ = ec != 0; + if(failed_) + return; + } + websocket_helpers::call_teardown(next_layer(), ec); + failed_ = ec != 0; + if(failed_) + return; + ec = error::failed; + failed_ = true; + return; + } + if(! ec) + websocket_helpers::call_teardown(next_layer(), ec); + if(! ec) + ec = error::closed; + failed_ = ec != 0; +} + +//------------------------------------------------------------------------------ + +// read an entire message +// +template +template +class stream::read_op +{ + struct data + { + bool cont; + stream& ws; + opcode& op; + DynamicBuffer& db; + frame_info fi; + int state = 0; + + data(Handler& handler, + stream& ws_, opcode& op_, + DynamicBuffer& sb_) + : cont(beast_asio_helpers:: + is_continuation(handler)) + , ws(ws_) + , op(op_) + , db(sb_) + { + } + }; + + handler_ptr d_; + +public: + read_op(read_op&&) = default; + read_op(read_op const&) = default; + + template + read_op(DeducedHandler&& h, + stream& ws, Args&&... args) + : d_(make_handler_ptr( + std::forward(h), ws, + std::forward(args)...)) + { + (*this)(error_code{}, false); + } + + void operator()( + error_code const& ec, bool again = true); + + friend + void* asio_handler_allocate( + std::size_t size, read_op* op) + { + return beast_asio_helpers:: + allocate(size, op->d_.handler()); + } + + friend + void asio_handler_deallocate( + void* p, std::size_t size, read_op* op) + { + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); + } + + friend + bool asio_handler_is_continuation(read_op* op) + { + return op->d_->cont; + } + + template + friend + void asio_handler_invoke(Function&& f, read_op* op) + { + return beast_asio_helpers:: + invoke(f, op->d_.handler()); + } +}; + +template +template +void +stream::read_op:: +operator()(error_code const& ec, bool again) +{ + auto& d = *d_; + d.cont = d.cont || again; + while(! ec) + { + switch(d.state) + { + case 0: + // read payload + d.state = 1; +#if 0 + // VFALCO This causes dereference of null, because + // the handler is moved from the data block + // before asio_handler_deallocate is called. + d.ws.async_read_frame( + d.fi, d.db, std::move(*this)); +#else + d.ws.async_read_frame(d.fi, d.db, *this); +#endif + return; + + // got payload + case 1: + d.op = d.fi.op; + if(d.fi.fin) + goto upcall; + d.state = 0; + break; + } + } +upcall: + d_.invoke(ec); +} + +template +template +typename async_completion< + ReadHandler, void(error_code)>::result_type +stream:: +async_read(opcode& op, + DynamicBuffer& dynabuf, ReadHandler&& handler) +{ + static_assert(is_AsyncStream::value, + "AsyncStream requirements requirements not met"); + static_assert(beast::is_DynamicBuffer::value, + "DynamicBuffer requirements not met"); + beast::async_completion< + ReadHandler, void(error_code) + > completion(handler); + read_op{ + completion.handler, *this, op, dynabuf}; + return completion.result.get(); +} + +template +template +void +stream:: +read(opcode& op, DynamicBuffer& dynabuf) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + static_assert(beast::is_DynamicBuffer::value, + "DynamicBuffer requirements not met"); + error_code ec; + read(op, dynabuf, ec); + if(ec) + throw system_error{ec}; +} + +template +template +void +stream:: +read(opcode& op, DynamicBuffer& dynabuf, error_code& ec) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + static_assert(beast::is_DynamicBuffer::value, + "DynamicBuffer requirements not met"); + frame_info fi; + for(;;) + { + read_frame(fi, dynabuf, ec); + if(ec) + break; + op = fi.op; + if(fi.fin) + break; + } +} + +//------------------------------------------------------------------------------ + } // websocket } // beast diff --git a/include/beast/websocket/impl/read_op.ipp b/include/beast/websocket/impl/read_op.ipp deleted file mode 100644 index 35fa3a0c6..000000000 --- a/include/beast/websocket/impl/read_op.ipp +++ /dev/null @@ -1,142 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_WEBSOCKET_IMPL_READ_OP_HPP -#define BEAST_WEBSOCKET_IMPL_READ_OP_HPP - -#include -#include - -namespace beast { -namespace websocket { - -// read an entire message -// -template -template -class stream::read_op -{ - using alloc_type = - handler_alloc; - - struct data - { - stream& ws; - opcode& op; - DynamicBuffer& db; - Handler h; - frame_info fi; - bool cont; - int state = 0; - - template - data(DeducedHandler&& h_, - stream& ws_, opcode& op_, - DynamicBuffer& sb_) - : ws(ws_) - , op(op_) - , db(sb_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) - { - } - }; - - std::shared_ptr d_; - -public: - read_op(read_op&&) = default; - read_op(read_op const&) = default; - - template - read_op(DeducedHandler&& h, - stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, - std::forward(h), ws, - std::forward(args)...)) - { - (*this)(error_code{}, false); - } - - void operator()( - error_code const& ec, bool again = true); - - friend - void* asio_handler_allocate( - std::size_t size, read_op* op) - { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); - } - - friend - void asio_handler_deallocate( - void* p, std::size_t size, read_op* op) - { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); - } - - friend - bool asio_handler_is_continuation(read_op* op) - { - return op->d_->cont; - } - - template - friend - void asio_handler_invoke(Function&& f, read_op* op) - { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); - } -}; - -template -template -void -stream::read_op:: -operator()(error_code const& ec, bool again) -{ - auto& d = *d_; - d.cont = d.cont || again; - while(! ec) - { - switch(d.state) - { - case 0: - // read payload - d.state = 1; -#if 0 - // VFALCO This causes dereference of null, because - // the handler is moved from the data block - // before asio_handler_deallocate is called. - d.ws.async_read_frame( - d.fi, d.db, std::move(*this)); -#else - d.ws.async_read_frame(d.fi, d.db, *this); -#endif - return; - - // got payload - case 1: - d.op = d.fi.op; - if(d.fi.fin) - goto upcall; - d.state = 0; - break; - } - } -upcall: - d.h(ec); -} - -} // websocket -} // beast - -#endif diff --git a/include/beast/websocket/impl/response_op.ipp b/include/beast/websocket/impl/response_op.ipp deleted file mode 100644 index 39af5c7b4..000000000 --- a/include/beast/websocket/impl/response_op.ipp +++ /dev/null @@ -1,139 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_WEBSOCKET_IMPL_RESPONSE_OP_HPP -#define BEAST_WEBSOCKET_IMPL_RESPONSE_OP_HPP - -#include -#include -#include -#include -#include - -namespace beast { -namespace websocket { - -// Respond to an upgrade HTTP request -template -template -class stream::response_op -{ - using alloc_type = - handler_alloc; - - struct data - { - stream& ws; - http::response_v1 resp; - Handler h; - error_code final_ec; - bool cont; - int state = 0; - - template - data(DeducedHandler&& h_, stream& ws_, - http::request_v1 const& req, - bool cont_) - : ws(ws_) - , resp(ws_.build_response(req)) - , h(std::forward(h_)) - , cont(cont_) - { - // can't call stream::reset() here - // otherwise accept_op will malfunction - // - if(resp.status != 101) - final_ec = error::handshake_failed; - } - }; - - std::shared_ptr d_; - -public: - response_op(response_op&&) = default; - response_op(response_op const&) = default; - - template - response_op(DeducedHandler&& h, - stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, - std::forward(h), ws, - std::forward(args)...)) - { - (*this)(error_code{}, false); - } - - void operator()( - error_code ec, bool again = true); - - friend - void* asio_handler_allocate( - std::size_t size, response_op* op) - { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); - } - - friend - void asio_handler_deallocate( - void* p, std::size_t size, response_op* op) - { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); - } - - friend - bool asio_handler_is_continuation(response_op* op) - { - return op->d_->cont; - } - - template - friend - void asio_handler_invoke(Function&& f, response_op* op) - { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); - } -}; - -template -template -void -stream::response_op:: -operator()(error_code ec, bool again) -{ - auto& d = *d_; - d.cont = d.cont || again; - while(! ec && d.state != 99) - { - switch(d.state) - { - case 0: - // send response - d.state = 1; - http::async_write(d.ws.next_layer(), - d.resp, std::move(*this)); - return; - - // sent response - case 1: - d.state = 99; - ec = d.final_ec; - if(! ec) - d.ws.open(detail::role_type::server); - break; - } - } - d.h(ec); -} - -} // websocket -} // beast - -#endif diff --git a/include/beast/websocket/impl/ssl.ipp b/include/beast/websocket/impl/ssl.ipp index 07570e5ce..5b3e5cf24 100644 --- a/include/beast/websocket/impl/ssl.ipp +++ b/include/beast/websocket/impl/ssl.ipp @@ -9,7 +9,9 @@ #define BEAST_WEBSOCKET_IMPL_SSL_IPP_INCLUDED #include +#include #include +#include namespace beast { namespace websocket { @@ -38,31 +40,28 @@ class teardown_ssl_op struct data { - stream_type& stream; - Handler h; bool cont; + stream_type& stream; int state = 0; - template - data(DeducedHandler&& h_, - stream_type& stream_) - : stream(stream_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) + data(Handler& handler, stream_type& stream_) + : cont(beast_asio_helpers:: + is_continuation(handler)) + , stream(stream_) { } }; - std::shared_ptr d_; + handler_ptr d_; public: template explicit teardown_ssl_op( DeducedHandler&& h, stream_type& stream) - : d_(std::make_shared( - std::forward(h), stream)) + : d_(make_handler_ptr( + std::forward( + h), stream)) { (*this)(error_code{}, false); } @@ -74,16 +73,16 @@ public: void* asio_handler_allocate(std::size_t size, teardown_ssl_op* op) { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + return beast_asio_helpers:: + allocate(size, op->d_.handler()); } friend void asio_handler_deallocate(void* p, std::size_t size, teardown_ssl_op* op) { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); } friend @@ -98,8 +97,8 @@ public: void asio_handler_invoke(Function&& f, teardown_ssl_op* op) { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + return beast_asio_helpers:: + invoke(f, op->d_.handler()); } }; @@ -120,7 +119,7 @@ operator()(error_code ec, bool again) return; } } - d.h(ec); + d_.invoke(ec); } } // detail diff --git a/include/beast/websocket/impl/stream.ipp b/include/beast/websocket/impl/stream.ipp index 4c69a032b..bd04db45a 100644 --- a/include/beast/websocket/impl/stream.ipp +++ b/include/beast/websocket/impl/stream.ipp @@ -10,15 +10,6 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include @@ -29,151 +20,15 @@ #include #include #include +#include #include #include -#include #include #include namespace beast { namespace websocket { -namespace detail { - -template -void -stream_base::open(role_type role) -{ - role_ = role; -} - -template -void -stream_base::prepare_fh(close_code::value& code) -{ - // continuation without an active message - if(! rd_cont_ && rd_fh_.op == opcode::cont) - { - code = close_code::protocol_error; - return; - } - // new data frame when continuation expected - if(rd_cont_ && ! is_control(rd_fh_.op) && - rd_fh_.op != opcode::cont) - { - code = close_code::protocol_error; - return; - } - if(rd_fh_.mask) - prepare_key(rd_key_, rd_fh_.key); - if(! is_control(rd_fh_.op)) - { - if(rd_fh_.op != opcode::cont) - { - rd_size_ = rd_fh_.len; - rd_opcode_ = rd_fh_.op; - } - else - { - if(rd_size_ > std::numeric_limits< - std::uint64_t>::max() - rd_fh_.len) - { - code = close_code::too_big; - return; - } - rd_size_ += rd_fh_.len; - } - if(rd_msg_max_ && rd_size_ > rd_msg_max_) - { - code = close_code::too_big; - return; - } - rd_need_ = rd_fh_.len; - rd_cont_ = ! rd_fh_.fin; - } -} - -template -void -stream_base::write_close( - DynamicBuffer& db, close_reason const& cr) -{ - using namespace boost::endian; - frame_header fh; - fh.op = opcode::close; - fh.fin = true; - fh.rsv1 = false; - fh.rsv2 = false; - fh.rsv3 = false; - fh.len = cr.code == close_code::none ? - 0 : 2 + cr.reason.size(); - fh.mask = role_ == detail::role_type::client; - if(fh.mask) - fh.key = maskgen_(); - detail::write(db, fh); - if(cr.code != close_code::none) - { - detail::prepared_key_type key; - if(fh.mask) - detail::prepare_key(key, fh.key); - { - std::uint8_t b[2]; - ::new(&b[0]) big_uint16_buf_t{ - (std::uint16_t)cr.code}; - auto d = db.prepare(2); - boost::asio::buffer_copy(d, - boost::asio::buffer(b)); - if(fh.mask) - detail::mask_inplace(d, key); - db.commit(2); - } - if(! cr.reason.empty()) - { - auto d = db.prepare(cr.reason.size()); - boost::asio::buffer_copy(d, - boost::asio::const_buffer( - cr.reason.data(), cr.reason.size())); - if(fh.mask) - detail::mask_inplace(d, key); - db.commit(cr.reason.size()); - } - } -} - -template -void -stream_base::write_ping(DynamicBuffer& db, - opcode op, ping_data const& data) -{ - frame_header fh; - fh.op = op; - fh.fin = true; - fh.rsv1 = false; - fh.rsv2 = false; - fh.rsv3 = false; - fh.len = data.size(); - fh.mask = role_ == role_type::client; - if(fh.mask) - fh.key = maskgen_(); - detail::write(db, fh); - if(data.empty()) - return; - detail::prepared_key_type key; - if(fh.mask) - detail::prepare_key(key, fh.key); - auto d = db.prepare(data.size()); - boost::asio::buffer_copy(d, - boost::asio::const_buffers_1( - data.data(), data.size())); - if(fh.mask) - detail::mask_inplace(d, key); - db.commit(data.size()); -} - -} // detail - -//------------------------------------------------------------------------------ - template template stream:: @@ -182,718 +37,6 @@ stream(Args&&... args) { } -template -void -stream:: -accept() -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - error_code ec; - accept(boost::asio::null_buffers{}, ec); - if(ec) - throw system_error{ec}; -} - -template -void -stream:: -accept(error_code& ec) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - accept(boost::asio::null_buffers{}, ec); -} - -template -template -typename async_completion< - AcceptHandler, void(error_code)>::result_type -stream:: -async_accept(AcceptHandler&& handler) -{ - static_assert(is_AsyncStream::value, - "AsyncStream requirements requirements not met"); - return async_accept(boost::asio::null_buffers{}, - std::forward(handler)); -} - -template -template -void -stream:: -accept(ConstBufferSequence const& buffers) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - static_assert(is_ConstBufferSequence< - ConstBufferSequence>::value, - "ConstBufferSequence requirements not met"); - error_code ec; - accept(buffers, ec); - if(ec) - throw system_error{ec}; -} - -template -template -void -stream:: -accept(ConstBufferSequence const& buffers, error_code& ec) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - static_assert(beast::is_ConstBufferSequence< - ConstBufferSequence>::value, - "ConstBufferSequence requirements not met"); - using boost::asio::buffer_copy; - using boost::asio::buffer_size; - reset(); - stream_.buffer().commit(buffer_copy( - stream_.buffer().prepare( - buffer_size(buffers)), buffers)); - http::request_v1 m; - http::read(next_layer(), stream_.buffer(), m, ec); - if(ec) - return; - accept(m, ec); -} - -template -template -typename async_completion< - AcceptHandler, void(error_code)>::result_type -stream:: -async_accept(ConstBufferSequence const& bs, AcceptHandler&& handler) -{ - static_assert(is_AsyncStream::value, - "AsyncStream requirements requirements not met"); - static_assert(beast::is_ConstBufferSequence< - ConstBufferSequence>::value, - "ConstBufferSequence requirements not met"); - beast::async_completion< - AcceptHandler, void(error_code) - > completion(handler); - accept_op{ - completion.handler, *this, bs}; - return completion.result.get(); -} - -template -template -void -stream:: -accept(http::request_v1 const& request) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - error_code ec; - accept(request, ec); - if(ec) - throw system_error{ec}; -} - -template -template -void -stream:: -accept(http::request_v1 const& req, - error_code& ec) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - reset(); - auto const res = build_response(req); - http::write(stream_, res, ec); - if(ec) - return; - if(res.status != 101) - { - ec = error::handshake_failed; - // VFALCO TODO Respect keep alive setting, perform - // teardown if Connection: close. - return; - } - open(detail::role_type::server); -} - -template -template -typename async_completion< - AcceptHandler, void(error_code)>::result_type -stream:: -async_accept(http::request_v1 const& req, - AcceptHandler&& handler) -{ - static_assert(is_AsyncStream::value, - "AsyncStream requirements requirements not met"); - beast::async_completion< - AcceptHandler, void(error_code) - > completion(handler); - reset(); - response_op{ - completion.handler, *this, req, - boost_asio_handler_cont_helpers:: - is_continuation(completion.handler)}; - return completion.result.get(); -} - -template -void -stream:: -handshake(boost::string_ref const& host, - boost::string_ref const& resource) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - error_code ec; - handshake(host, resource, ec); - if(ec) - throw system_error{ec}; -} - -template -void -stream:: -handshake(boost::string_ref const& host, - boost::string_ref const& resource, error_code& ec) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - reset(); - std::string key; - http::write(stream_, - build_request(host, resource, key), ec); - if(ec) - return; - http::response_v1 res; - http::read(next_layer(), stream_.buffer(), res, ec); - if(ec) - return; - do_response(res, key, ec); -} - -template -template -typename async_completion< - HandshakeHandler, void(error_code)>::result_type -stream:: -async_handshake(boost::string_ref const& host, - boost::string_ref const& resource, HandshakeHandler&& handler) -{ - static_assert(is_AsyncStream::value, - "AsyncStream requirements not met"); - beast::async_completion< - HandshakeHandler, void(error_code) - > completion(handler); - handshake_op{ - completion.handler, *this, host, resource}; - return completion.result.get(); -} - -template -void -stream:: -close(close_reason const& cr) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - error_code ec; - close(cr, ec); - if(ec) - throw system_error{ec}; -} - -template -void -stream:: -close(close_reason const& cr, error_code& ec) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - assert(! wr_close_); - wr_close_ = true; - detail::frame_streambuf fb; - write_close(fb, cr); - boost::asio::write(stream_, fb.data(), ec); - failed_ = ec != 0; -} - -template -template -typename async_completion< - CloseHandler, void(error_code)>::result_type -stream:: -async_close(close_reason const& cr, CloseHandler&& handler) -{ - static_assert(is_AsyncStream::value, - "AsyncStream requirements not met"); - beast::async_completion< - CloseHandler, void(error_code) - > completion(handler); - close_op{ - completion.handler, *this, cr}; - return completion.result.get(); -} - -template -void -stream:: -ping(ping_data const& payload) -{ - error_code ec; - ping(payload, ec); - if(ec) - throw system_error{ec}; -} - -template -void -stream:: -ping(ping_data const& payload, error_code& ec) -{ - detail::frame_streambuf db; - write_ping( - db, opcode::ping, payload); - boost::asio::write(stream_, db.data(), ec); -} - -template -template -typename async_completion< - PingHandler, void(error_code)>::result_type -stream:: -async_ping(ping_data const& payload, PingHandler&& handler) -{ - static_assert(is_AsyncStream::value, - "AsyncStream requirements requirements not met"); - beast::async_completion< - PingHandler, void(error_code) - > completion(handler); - ping_op{ - completion.handler, *this, payload}; - return completion.result.get(); -} - -template -template -void -stream:: -read(opcode& op, DynamicBuffer& dynabuf) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - static_assert(beast::is_DynamicBuffer::value, - "DynamicBuffer requirements not met"); - error_code ec; - read(op, dynabuf, ec); - if(ec) - throw system_error{ec}; -} - -template -template -void -stream:: -read(opcode& op, DynamicBuffer& dynabuf, error_code& ec) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - static_assert(beast::is_DynamicBuffer::value, - "DynamicBuffer requirements not met"); - frame_info fi; - for(;;) - { - read_frame(fi, dynabuf, ec); - if(ec) - break; - op = fi.op; - if(fi.fin) - break; - } -} - -template -template -typename async_completion< - ReadHandler, void(error_code)>::result_type -stream:: -async_read(opcode& op, - DynamicBuffer& dynabuf, ReadHandler&& handler) -{ - static_assert(is_AsyncStream::value, - "AsyncStream requirements requirements not met"); - static_assert(beast::is_DynamicBuffer::value, - "DynamicBuffer requirements not met"); - beast::async_completion< - ReadHandler, void(error_code) - > completion(handler); - read_op{ - completion.handler, *this, op, dynabuf}; - return completion.result.get(); -} - -template -template -void -stream:: -read_frame(frame_info& fi, DynamicBuffer& dynabuf) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - static_assert(beast::is_DynamicBuffer::value, - "DynamicBuffer requirements not met"); - error_code ec; - read_frame(fi, dynabuf, ec); - if(ec) - throw system_error{ec}; -} - -template -template -void -stream:: -read_frame(frame_info& fi, DynamicBuffer& dynabuf, error_code& ec) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - static_assert(beast::is_DynamicBuffer::value, - "DynamicBuffer requirements not met"); - close_code::value code{}; - for(;;) - { - if(rd_need_ == 0) - { - // read header - detail::frame_streambuf fb; - do_read_fh(fb, code, ec); - failed_ = ec != 0; - if(failed_) - return; - if(code != close_code::none) - break; - if(detail::is_control(rd_fh_.op)) - { - // read control payload - if(rd_fh_.len > 0) - { - auto const mb = fb.prepare( - static_cast(rd_fh_.len)); - fb.commit(boost::asio::read(stream_, mb, ec)); - failed_ = ec != 0; - if(failed_) - return; - if(rd_fh_.mask) - detail::mask_inplace(mb, rd_key_); - fb.commit(static_cast(rd_fh_.len)); - } - if(rd_fh_.op == opcode::ping) - { - ping_data data; - detail::read(data, fb.data()); - fb.reset(); - write_ping( - fb, opcode::pong, data); - boost::asio::write(stream_, fb.data(), ec); - failed_ = ec != 0; - if(failed_) - return; - continue; - } - else if(rd_fh_.op == opcode::pong) - { - ping_data payload; - detail::read(payload, fb.data()); - if(pong_cb_) - pong_cb_(payload); - continue; - } - assert(rd_fh_.op == opcode::close); - { - detail::read(cr_, fb.data(), code); - if(code != close_code::none) - break; - if(! wr_close_) - { - auto cr = cr_; - if(cr.code == close_code::none) - cr.code = close_code::normal; - cr.reason = ""; - fb.reset(); - wr_close_ = true; - write_close(fb, cr); - boost::asio::write(stream_, fb.data(), ec); - failed_ = ec != 0; - if(failed_) - return; - } - break; - } - } - if(rd_need_ == 0 && ! rd_fh_.fin) - { - // empty frame - continue; - } - } - // read payload - auto smb = dynabuf.prepare( - detail::clamp(rd_need_)); - auto const bytes_transferred = - stream_.read_some(smb, ec); - failed_ = ec != 0; - if(failed_) - return; - rd_need_ -= bytes_transferred; - auto const pb = prepare_buffers( - bytes_transferred, smb); - if(rd_fh_.mask) - detail::mask_inplace(pb, rd_key_); - if(rd_opcode_ == opcode::text) - { - if(! rd_utf8_check_.write(pb) || - (rd_need_ == 0 && rd_fh_.fin && - ! rd_utf8_check_.finish())) - { - code = close_code::bad_payload; - break; - } - } - dynabuf.commit(bytes_transferred); - fi.op = rd_opcode_; - fi.fin = rd_fh_.fin && rd_need_ == 0; - return; - } - if(code != close_code::none) - { - // Fail the connection (per rfc6455) - if(! wr_close_) - { - wr_close_ = true; - detail::frame_streambuf fb; - write_close(fb, code); - boost::asio::write(stream_, fb.data(), ec); - failed_ = ec != 0; - if(failed_) - return; - } - websocket_helpers::call_teardown(next_layer(), ec); - failed_ = ec != 0; - if(failed_) - return; - ec = error::failed; - failed_ = true; - return; - } - if(! ec) - websocket_helpers::call_teardown(next_layer(), ec); - if(! ec) - ec = error::closed; - failed_ = ec != 0; -} - -template -template -typename async_completion< - ReadHandler, void(error_code)>::result_type -stream:: -async_read_frame(frame_info& fi, - DynamicBuffer& dynabuf, ReadHandler&& handler) -{ - static_assert(is_AsyncStream::value, - "AsyncStream requirements requirements not met"); - static_assert(beast::is_DynamicBuffer::value, - "DynamicBuffer requirements not met"); - beast::async_completion< - ReadHandler, void(error_code)> completion(handler); - read_frame_op{ - completion.handler, *this, fi, dynabuf}; - return completion.result.get(); -} - -template -template -void -stream:: -write(ConstBufferSequence const& buffers) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - static_assert(beast::is_ConstBufferSequence< - ConstBufferSequence>::value, - "ConstBufferSequence requirements not met"); - error_code ec; - write(buffers, ec); - if(ec) - throw system_error{ec}; -} - -template -template -void -stream:: -write(ConstBufferSequence const& bs, error_code& ec) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - static_assert(beast::is_ConstBufferSequence< - ConstBufferSequence>::value, - "ConstBufferSequence requirements not met"); - using boost::asio::buffer_size; - consuming_buffers cb(bs); - auto remain = buffer_size(cb); - for(;;) - { - auto const n = - detail::clamp(remain, wr_frag_size_); - remain -= n; - auto const fin = remain <= 0; - write_frame(fin, prepare_buffers(n, cb), ec); - cb.consume(n); - if(ec) - return; - if(fin) - break; - } -} - -template -template -typename async_completion< - WriteHandler, void(error_code)>::result_type -stream:: -async_write(ConstBufferSequence const& bs, WriteHandler&& handler) -{ - static_assert(is_AsyncStream::value, - "AsyncStream requirements not met"); - static_assert(beast::is_ConstBufferSequence< - ConstBufferSequence>::value, - "ConstBufferSequence requirements not met"); - beast::async_completion< - WriteHandler, void(error_code)> completion(handler); - write_op{ - completion.handler, *this, bs}; - return completion.result.get(); -} - -template -template -void -stream:: -write_frame(bool fin, ConstBufferSequence const& buffers) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - static_assert(beast::is_ConstBufferSequence< - ConstBufferSequence>::value, - "ConstBufferSequence requirements not met"); - error_code ec; - write_frame(fin, buffers, ec); - if(ec) - throw system_error{ec}; -} - -template -template -void -stream:: -write_frame(bool fin, ConstBufferSequence const& bs, error_code& ec) -{ - static_assert(is_SyncStream::value, - "SyncStream requirements not met"); - static_assert(beast::is_ConstBufferSequence< - ConstBufferSequence>::value, - "ConstBufferSequence requirements not met"); - using boost::asio::buffer_copy; - using boost::asio::buffer_size; - using boost::asio::mutable_buffers_1; - detail::frame_header fh; - fh.op = wr_cont_ ? opcode::cont : wr_opcode_; - wr_cont_ = ! fin; - fh.fin = fin; - fh.rsv1 = false; - fh.rsv2 = false; - fh.rsv3 = false; - fh.len = buffer_size(bs); - fh.mask = role_ == detail::role_type::client; - if(fh.mask) - fh.key = maskgen_(); - detail::fh_streambuf fh_buf; - detail::write(fh_buf, fh); - if(! fh.mask) - { - // send header and payload - boost::asio::write(stream_, - buffer_cat(fh_buf.data(), bs), ec); - failed_ = ec != 0; - return; - } - detail::prepared_key_type key; - detail::prepare_key(key, fh.key); - auto const tmp_size = - detail::clamp(fh.len, mask_buf_size_); - std::unique_ptr up( - new std::uint8_t[tmp_size]); - std::uint64_t remain = fh.len; - consuming_buffers cb(bs); - { - auto const n = - detail::clamp(remain, tmp_size); - mutable_buffers_1 mb{up.get(), n}; - buffer_copy(mb, cb); - cb.consume(n); - remain -= n; - detail::mask_inplace(mb, key); - // send header and payload - boost::asio::write(stream_, - buffer_cat(fh_buf.data(), mb), ec); - if(ec) - { - failed_ = ec != 0; - return; - } - } - while(remain > 0) - { - auto const n = - detail::clamp(remain, tmp_size); - mutable_buffers_1 mb{up.get(), n}; - buffer_copy(mb, cb); - cb.consume(n); - remain -= n; - detail::mask_inplace(mb, key); - // send payload - boost::asio::write(stream_, mb, ec); - if(ec) - { - failed_ = ec != 0; - return; - } - } -} - -template -template -typename async_completion< - WriteHandler, void(error_code)>::result_type -stream:: -async_write_frame(bool fin, - ConstBufferSequence const& bs, WriteHandler&& handler) -{ - static_assert(is_AsyncStream::value, - "AsyncStream requirements not met"); - static_assert(beast::is_ConstBufferSequence< - ConstBufferSequence>::value, - "ConstBufferSequence requirements not met"); - beast::async_completion< - WriteHandler, void(error_code) - > completion(handler); - write_frame_op{completion.handler, - *this, fin, bs}; - return completion.result.get(); -} - //------------------------------------------------------------------------------ template @@ -905,7 +48,7 @@ reset() rd_need_ = 0; rd_cont_ = false; wr_close_ = false; - wr_cont_ = false; + wr_.cont = false; wr_block_ = nullptr; // should be nullptr on close anyway pong_data_ = nullptr; // should be nullptr on close anyway @@ -914,35 +57,35 @@ reset() } template -http::request_v1 +http::request stream:: build_request(boost::string_ref const& host, boost::string_ref const& resource, std::string& key) { - http::request_v1 req; + http::request req; req.url = { resource.data(), resource.size() }; req.version = 11; req.method = "GET"; - req.headers.insert("Host", host); - req.headers.insert("Upgrade", "websocket"); + req.fields.insert("Host", host); + req.fields.insert("Upgrade", "websocket"); key = detail::make_sec_ws_key(maskgen_); - req.headers.insert("Sec-WebSocket-Key", key); - req.headers.insert("Sec-WebSocket-Version", "13"); + req.fields.insert("Sec-WebSocket-Key", key); + req.fields.insert("Sec-WebSocket-Version", "13"); (*d_)(req); http::prepare(req, http::connection::upgrade); return req; } template -template -http::response_v1 +template +http::response stream:: -build_response(http::request_v1 const& req) +build_response(http::request const& req) { auto err = [&](std::string const& text) { - http::response_v1 res; + http::response res; res.status = 400; res.reason = http::reason_string(res.status); res.version = req.version; @@ -960,24 +103,24 @@ build_response(http::request_v1 const& req) return err("Wrong method"); if(! is_upgrade(req)) return err("Expected Upgrade request"); - if(! req.headers.exists("Host")) + if(! req.fields.exists("Host")) return err("Missing Host"); - if(! req.headers.exists("Sec-WebSocket-Key")) + if(! req.fields.exists("Sec-WebSocket-Key")) return err("Missing Sec-WebSocket-Key"); - if(! http::token_list{req.headers["Upgrade"]}.exists("websocket")) + if(! http::token_list{req.fields["Upgrade"]}.exists("websocket")) return err("Missing websocket Upgrade token"); { auto const version = - req.headers["Sec-WebSocket-Version"]; + req.fields["Sec-WebSocket-Version"]; if(version.empty()) return err("Missing Sec-WebSocket-Version"); if(version != "13") { - http::response_v1 res; + http::response res; res.status = 426; res.reason = http::reason_string(res.status); res.version = req.version; - res.headers.insert("Sec-WebSocket-Version", "13"); + res.fields.insert("Sec-WebSocket-Version", "13"); prepare(res, (is_keep_alive(req) && keep_alive_) ? http::connection::keep_alive : @@ -985,28 +128,28 @@ build_response(http::request_v1 const& req) return res; } } - http::response_v1 res; + http::response res; res.status = 101; res.reason = http::reason_string(res.status); res.version = req.version; - res.headers.insert("Upgrade", "websocket"); + res.fields.insert("Upgrade", "websocket"); { auto const key = - req.headers["Sec-WebSocket-Key"]; - res.headers.insert("Sec-WebSocket-Accept", + req.fields["Sec-WebSocket-Key"]; + res.fields.insert("Sec-WebSocket-Accept", detail::make_sec_ws_accept(key)); } - res.headers.replace("Server", "Beast.WSProto"); + res.fields.replace("Server", "Beast.WSProto"); (*d_)(res); http::prepare(res, http::connection::upgrade); return res; } template -template +template void stream:: -do_response(http::response_v1 const& res, +do_response(http::response const& res, boost::string_ref const& key, error_code& ec) { // VFALCO Review these error codes @@ -1017,11 +160,11 @@ do_response(http::response_v1 const& res, return fail(); if(! is_upgrade(res)) return fail(); - if(! http::token_list{res.headers["Upgrade"]}.exists("websocket")) + if(! http::token_list{res.fields["Upgrade"]}.exists("websocket")) return fail(); - if(! res.headers.exists("Sec-WebSocket-Accept")) + if(! res.fields.exists("Sec-WebSocket-Accept")) return fail(); - if(res.headers["Sec-WebSocket-Accept"] != + if(res.fields["Sec-WebSocket-Accept"] != detail::make_sec_ws_accept(key)) return fail(); open(detail::role_type::client); @@ -1037,8 +180,7 @@ do_read_fh(detail::frame_streambuf& fb, stream_, fb.prepare(2), ec)); if(ec) return; - auto const n = detail::read_fh1( - rd_fh_, fb, role_, code); + auto const n = read_fh1(fb, code); if(code != close_code::none) return; if(n > 0) @@ -1048,11 +190,7 @@ do_read_fh(detail::frame_streambuf& fb, if(ec) return; } - detail::read_fh2( - rd_fh_, fb, role_, code); - if(code != close_code::none) - return; - prepare_fh(code); + read_fh2(fb, code); } } // websocket diff --git a/include/beast/websocket/impl/teardown.ipp b/include/beast/websocket/impl/teardown.ipp index 4de5444bc..b2ac39918 100644 --- a/include/beast/websocket/impl/teardown.ipp +++ b/include/beast/websocket/impl/teardown.ipp @@ -10,6 +10,8 @@ #include #include +#include +#include #include namespace beast { @@ -25,32 +27,29 @@ class teardown_tcp_op struct data { - socket_type& socket; - Handler h; - char buf[8192]; bool cont; + socket_type& socket; + char buf[2048]; int state = 0; - template - data(DeducedHandler&& h_, socket_type& socket_) - : socket(socket_) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) + data(Handler& handler, socket_type& socket_) + : cont(beast_asio_helpers:: + is_continuation(handler)) + , socket(socket_) { } }; - std::shared_ptr d_; + handler_ptr d_; public: template teardown_tcp_op( DeducedHandler&& h, socket_type& socket) - : d_(std::make_shared( - std::forward(h), - socket)) + : d_(make_handler_ptr( + std::forward( + h), socket)) { (*this)(error_code{}, 0, false); } @@ -62,16 +61,16 @@ public: void* asio_handler_allocate(std::size_t size, teardown_tcp_op* op) { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); + return beast_asio_helpers:: + allocate(size, op->d_.handler()); } friend void asio_handler_deallocate(void* p, std::size_t size, teardown_tcp_op* op) { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); } friend @@ -85,8 +84,8 @@ public: void asio_handler_invoke(Function&& f, teardown_tcp_op* op) { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); + return beast_asio_helpers:: + invoke(f, op->d_.handler()); } }; @@ -119,7 +118,7 @@ operator()(error_code ec, std::size_t, bool again) d.socket.close(ec); ec = error_code{}; } - d.h(ec); + d_.invoke(ec); } } // detail diff --git a/include/beast/websocket/impl/write.ipp b/include/beast/websocket/impl/write.ipp new file mode 100644 index 000000000..48032314e --- /dev/null +++ b/include/beast/websocket/impl/write.ipp @@ -0,0 +1,683 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_WEBSOCKET_IMPL_WRITE_IPP +#define BEAST_WEBSOCKET_IMPL_WRITE_IPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace websocket { + +/* + template + void + write_frame(bool fin, ConstBufferSequence const& buffer) + + Depending on the settings of autofragment role, and compression, + different algorithms are used. + + 1. autofragment: false + compression: false + + In the server role, this will send a single frame in one + system call, by concatenating the frame header and the payload. + + In the client role, this will send a single frame in one system + call, using the write buffer to calculate masked data. + + 2. autofragment: true + compression: false + + In the server role, this will send one or more frames in one + system call per sent frame. Each frame is sent by concatenating + the frame header and payload. The size of each sent frame will + not exceed the write buffer size option. + + In the client role, this will send one or more frames in one + system call per sent frame, using the write buffer to calculate + masked data. The size of each sent frame will not exceed the + write buffer size option. + + 3. autofragment: false + compression: true + + In the server role, this will... + +*/ +/* + if(compress) + compress buffers into write_buffer + if(write_buffer_avail == write_buffer_size || fin`) + if(mask) + apply mask to write buffer + write frame header, write_buffer as one frame + else if(auto-fragment) + if(fin || write_buffer_avail + buffers size == write_buffer_size) + if(mask) + append buffers to write buffer + apply mask to write buffer + write frame header, write buffer as one frame + + else: + write frame header, write buffer, and buffers as one frame + else: + append buffers to write buffer + else if(mask) + copy buffers to write_buffer + apply mask to write_buffer + write frame header and possibly full write_buffer in a single call + loop: + copy buffers to write_buffer + apply mask to write_buffer + write write_buffer in a single call + else + write frame header, buffers as one frame +*/ + +//------------------------------------------------------------------------------ + +template +template +class stream::write_frame_op +{ + struct data : op + { + Handler& handler; + bool cont; + stream& ws; + consuming_buffers cb; + detail::frame_header fh; + detail::fh_streambuf fh_buf; + detail::prepared_key_type key; + void* tmp; + std::size_t tmp_size; + std::uint64_t remain; + int state = 0; + + data(Handler& handler_, stream& ws_, + bool fin, Buffers const& bs) + : handler(handler_) + , cont(beast_asio_helpers:: + is_continuation(handler)) + , ws(ws_) + , cb(bs) + { + using beast::detail::clamp; + fh.op = ws.wr_.cont ? + opcode::cont : ws.wr_opcode_; + ws.wr_.cont = ! fin; + fh.fin = fin; + fh.rsv1 = false; + fh.rsv2 = false; + fh.rsv3 = false; + fh.len = boost::asio::buffer_size(cb); + fh.mask = ws.role_ == detail::role_type::client; + if(fh.mask) + { + fh.key = ws.maskgen_(); + detail::prepare_key(key, fh.key); + tmp_size = clamp(fh.len, ws.wr_buf_size_); + tmp = beast_asio_helpers:: + allocate(tmp_size, handler); + remain = fh.len; + } + else + { + tmp = nullptr; + } + detail::write(fh_buf, fh); + } + + ~data() + { + if(tmp) + beast_asio_helpers:: + deallocate(tmp, tmp_size, handler); + } + }; + + handler_ptr d_; + +public: + write_frame_op(write_frame_op&&) = default; + write_frame_op(write_frame_op const&) = default; + + template + write_frame_op(DeducedHandler&& h, + stream& ws, Args&&... args) + : d_(make_handler_ptr( + std::forward(h), + ws, std::forward(args)...)) + { + (*this)(error_code{}, false); + } + + void operator()() + { + (*this)(error_code{}); + } + + void operator()(error_code ec, std::size_t); + + void operator()(error_code ec, bool again = true); + + friend + void* asio_handler_allocate( + std::size_t size, write_frame_op* op) + { + return beast_asio_helpers:: + allocate(size, op->d_.handler()); + } + + friend + void asio_handler_deallocate( + void* p, std::size_t size, write_frame_op* op) + { + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); + } + + friend + bool asio_handler_is_continuation(write_frame_op* op) + { + return op->d_->cont; + } + + template + friend + void asio_handler_invoke(Function&& f, write_frame_op* op) + { + return beast_asio_helpers:: + invoke(f, op->d_.handler()); + } +}; + +template +template +void +stream:: +write_frame_op:: +operator()(error_code ec, std::size_t) +{ + auto& d = *d_; + if(ec) + d.ws.failed_ = true; + (*this)(ec); +} + +template +template +void +stream:: +write_frame_op:: +operator()(error_code ec, bool again) +{ + using beast::detail::clamp; + using boost::asio::buffer_copy; + using boost::asio::mutable_buffers_1; + auto& d = *d_; + d.cont = d.cont || again; + if(ec) + goto upcall; + for(;;) + { + switch(d.state) + { + case 0: + if(d.ws.wr_block_) + { + // suspend + d.state = 3; + d.ws.wr_op_.template emplace< + write_frame_op>(std::move(*this)); + return; + } + if(d.ws.failed_ || d.ws.wr_close_) + { + // call handler + d.state = 99; + d.ws.get_io_service().post( + bind_handler(std::move(*this), + boost::asio::error::operation_aborted)); + return; + } + // fall through + + case 1: + { + if(! d.fh.mask) + { + // send header and entire payload + d.state = 99; + BOOST_ASSERT(! d.ws.wr_block_); + d.ws.wr_block_ = &d; + boost::asio::async_write(d.ws.stream_, + buffer_cat(d.fh_buf.data(), d.cb), + std::move(*this)); + return; + } + auto const n = clamp(d.remain, d.tmp_size); + mutable_buffers_1 mb{d.tmp, n}; + buffer_copy(mb, d.cb); + d.cb.consume(n); + d.remain -= n; + detail::mask_inplace(mb, d.key); + // send header and payload + d.state = d.remain > 0 ? 2 : 99; + BOOST_ASSERT(! d.ws.wr_block_); + d.ws.wr_block_ = &d; + boost::asio::async_write(d.ws.stream_, + buffer_cat(d.fh_buf.data(), + mb), std::move(*this)); + return; + } + + // sent masked payload + case 2: + { + auto const n = clamp(d.remain, d.tmp_size); + mutable_buffers_1 mb{d.tmp, + static_cast(n)}; + buffer_copy(mb, d.cb); + d.cb.consume(n); + d.remain -= n; + detail::mask_inplace(mb, d.key); + // send payload + if(d.remain == 0) + d.state = 99; + BOOST_ASSERT(d.ws.wr_block_ == &d); + boost::asio::async_write( + d.ws.stream_, mb, std::move(*this)); + return; + } + + case 3: + d.state = 4; + d.ws.get_io_service().post(bind_handler( + std::move(*this), ec)); + return; + + case 4: + if(d.ws.failed_ || d.ws.wr_close_) + { + // call handler + ec = boost::asio::error::operation_aborted; + goto upcall; + } + d.state = 1; + break; + + case 99: + goto upcall; + } + } +upcall: + if(d.ws.wr_block_ == &d) + d.ws.wr_block_ = nullptr; + d.ws.rd_op_.maybe_invoke(); + d_.invoke(ec); +} + +template +template +typename async_completion< + WriteHandler, void(error_code)>::result_type +stream:: +async_write_frame(bool fin, + ConstBufferSequence const& bs, WriteHandler&& handler) +{ + static_assert(is_AsyncStream::value, + "AsyncStream requirements not met"); + static_assert(beast::is_ConstBufferSequence< + ConstBufferSequence>::value, + "ConstBufferSequence requirements not met"); + beast::async_completion< + WriteHandler, void(error_code) + > completion(handler); + write_frame_op{completion.handler, + *this, fin, bs}; + return completion.result.get(); +} + +template +template +void +stream:: +write_frame(bool fin, ConstBufferSequence const& buffers) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + static_assert(beast::is_ConstBufferSequence< + ConstBufferSequence>::value, + "ConstBufferSequence requirements not met"); + error_code ec; + write_frame(fin, buffers, ec); + if(ec) + throw system_error{ec}; +} + +template +template +void +stream:: +write_frame(bool fin, + ConstBufferSequence const& buffers, error_code& ec) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + static_assert(beast::is_ConstBufferSequence< + ConstBufferSequence>::value, + "ConstBufferSequence requirements not met"); + using beast::detail::clamp; + using boost::asio::buffer; + using boost::asio::buffer_copy; + using boost::asio::buffer_size; + bool const compress = false; + if(! wr_.cont) + wr_prepare(compress); + detail::frame_header fh; + fh.op = wr_.cont ? opcode::cont : wr_opcode_; + fh.rsv1 = false; + fh.rsv2 = false; + fh.rsv3 = false; + fh.mask = role_ == detail::role_type::client; + wr_.cont = ! fin; + auto remain = buffer_size(buffers); + if(compress) + { + // TODO + } + else if(! fh.mask && ! wr_.autofrag) + { + fh.fin = fin; + fh.len = remain; + detail::fh_streambuf fh_buf; + detail::write(fh_buf, fh); + boost::asio::write(stream_, + buffer_cat(fh_buf.data(), buffers), ec); + failed_ = ec != 0; + if(failed_) + return; + return; + } + else if(! fh.mask && wr_.autofrag) + { + BOOST_ASSERT(wr_.size != 0); + consuming_buffers< + ConstBufferSequence> cb(buffers); + for(;;) + { + auto const n = clamp(remain, wr_.size); + fh.len = n; + remain -= n; + fh.fin = fin ? remain == 0 : false; + detail::fh_streambuf fh_buf; + detail::write(fh_buf, fh); + boost::asio::write(stream_, + buffer_cat(fh_buf.data(), + prepare_buffers(n, cb)), ec); + failed_ = ec != 0; + if(failed_) + return; + if(remain == 0) + break; + fh.op = opcode::cont; + cb.consume(n); + } + return; + } + else if(fh.mask && ! wr_.autofrag) + { + fh.key = maskgen_(); + detail::prepared_key_type key; + detail::prepare_key(key, fh.key); + fh.fin = fin; + fh.len = remain; + detail::fh_streambuf fh_buf; + detail::write(fh_buf, fh); + consuming_buffers< + ConstBufferSequence> cb(buffers); + { + auto const n = clamp(remain, wr_.size); + auto const mb = buffer(wr_.buf.get(), n); + buffer_copy(mb, cb); + cb.consume(n); + remain -= n; + detail::mask_inplace(mb, key); + boost::asio::write(stream_, + buffer_cat(fh_buf.data(), mb), ec); + failed_ = ec != 0; + if(failed_) + return; + } + while(remain > 0) + { + auto const n = clamp(remain, wr_.size); + auto const mb = buffer(wr_.buf.get(), n); + buffer_copy(mb, cb); + cb.consume(n); + remain -= n; + detail::mask_inplace(mb, key); + boost::asio::write(stream_, mb, ec); + failed_ = ec != 0; + if(failed_) + return; + } + return; + } + else if(fh.mask && wr_.autofrag) + { + BOOST_ASSERT(wr_.size != 0); + consuming_buffers< + ConstBufferSequence> cb(buffers); + for(;;) + { + fh.key = maskgen_(); + detail::prepared_key_type key; + detail::prepare_key(key, fh.key); + auto const n = clamp(remain, wr_.size); + auto const mb = buffer(wr_.buf.get(), n); + buffer_copy(mb, cb); + detail::mask_inplace(mb, key); + fh.len = n; + remain -= n; + fh.fin = fin ? remain == 0 : false; + detail::fh_streambuf fh_buf; + detail::write(fh_buf, fh); + boost::asio::write(stream_, + buffer_cat(fh_buf.data(), mb), ec); + failed_ = ec != 0; + if(failed_) + return; + if(remain == 0) + break; + fh.op = opcode::cont; + cb.consume(n); + } + return; + } +} + +//------------------------------------------------------------------------------ + +template +template +class stream::write_op +{ + struct data : op + { + bool cont; + stream& ws; + consuming_buffers cb; + std::size_t remain; + int state = 0; + + data(Handler& handler, stream& ws_, + Buffers const& bs) + : cont(beast_asio_helpers:: + is_continuation(handler)) + , ws(ws_) + , cb(bs) + , remain(boost::asio::buffer_size(cb)) + { + } + }; + + handler_ptr d_; + +public: + write_op(write_op&&) = default; + write_op(write_op const&) = default; + + template + explicit + write_op(DeducedHandler&& h, + stream& ws, Args&&... args) + : d_(make_handler_ptr( + std::forward(h), ws, + std::forward(args)...)) + { + (*this)(error_code{}, false); + } + + void operator()(error_code ec, bool again = true); + + friend + void* asio_handler_allocate( + std::size_t size, write_op* op) + { + return beast_asio_helpers:: + allocate(size, op->d_.handler()); + } + + friend + void asio_handler_deallocate( + void* p, std::size_t size, write_op* op) + { + return beast_asio_helpers:: + deallocate(p, size, op->d_.handler()); + } + + friend + bool asio_handler_is_continuation(write_op* op) + { + return op->d_->cont; + } + + template + friend + void asio_handler_invoke(Function&& f, write_op* op) + { + return beast_asio_helpers:: + invoke(f, op->d_.handler()); + } +}; + +template +template +void +stream:: +write_op:: +operator()(error_code ec, bool again) +{ + auto& d = *d_; + d.cont = d.cont || again; + if(! ec) + { + switch(d.state) + { + case 0: + { + auto const n = d.remain; + d.remain -= n; + auto const fin = d.remain <= 0; + if(fin) + d.state = 99; + auto const pb = prepare_buffers(n, d.cb); + d.cb.consume(n); + d.ws.async_write_frame(fin, pb, std::move(*this)); + return; + } + + case 99: + break; + } + } + d_.invoke(ec); +} + +template +template +typename async_completion< + WriteHandler, void(error_code)>::result_type +stream:: +async_write(ConstBufferSequence const& bs, WriteHandler&& handler) +{ + static_assert(is_AsyncStream::value, + "AsyncStream requirements not met"); + static_assert(beast::is_ConstBufferSequence< + ConstBufferSequence>::value, + "ConstBufferSequence requirements not met"); + beast::async_completion< + WriteHandler, void(error_code)> completion(handler); + write_op{ + completion.handler, *this, bs}; + return completion.result.get(); +} + +template +template +void +stream:: +write(ConstBufferSequence const& buffers) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + static_assert(beast::is_ConstBufferSequence< + ConstBufferSequence>::value, + "ConstBufferSequence requirements not met"); + error_code ec; + write(buffers, ec); + if(ec) + throw system_error{ec}; +} + +template +template +void +stream:: +write(ConstBufferSequence const& buffers, error_code& ec) +{ + static_assert(is_SyncStream::value, + "SyncStream requirements not met"); + static_assert(beast::is_ConstBufferSequence< + ConstBufferSequence>::value, + "ConstBufferSequence requirements not met"); + write_frame(true, buffers, ec); +} + +//------------------------------------------------------------------------------ + +} // websocket +} // beast + +#endif diff --git a/include/beast/websocket/impl/write_frame_op.ipp b/include/beast/websocket/impl/write_frame_op.ipp deleted file mode 100644 index 2bc9e74f8..000000000 --- a/include/beast/websocket/impl/write_frame_op.ipp +++ /dev/null @@ -1,282 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_WEBSOCKET_IMPL_WRITE_FRAME_OP_HPP -#define BEAST_WEBSOCKET_IMPL_WRITE_FRAME_OP_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace beast { -namespace websocket { - -// write a frame -// -template -template -class stream::write_frame_op -{ - using alloc_type = - handler_alloc; - - struct data : op - { - stream& ws; - consuming_buffers cb; - Handler h; - detail::frame_header fh; - detail::fh_streambuf fh_buf; - detail::prepared_key_type key; - void* tmp; - std::size_t tmp_size; - std::uint64_t remain; - bool cont; - int state = 0; - - template - data(DeducedHandler&& h_, stream& ws_, - bool fin, Buffers const& bs) - : ws(ws_) - , cb(bs) - , h(std::forward(h_)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) - { - fh.op = ws.wr_cont_ ? - opcode::cont : ws.wr_opcode_; - ws.wr_cont_ = ! fin; - fh.fin = fin; - fh.rsv1 = false; - fh.rsv2 = false; - fh.rsv3 = false; - fh.len = boost::asio::buffer_size(cb); - fh.mask = ws.role_ == detail::role_type::client; - if(fh.mask) - { - fh.key = ws.maskgen_(); - detail::prepare_key(key, fh.key); - tmp_size = detail::clamp( - fh.len, ws.mask_buf_size_); - tmp = boost_asio_handler_alloc_helpers:: - allocate(tmp_size, h); - remain = fh.len; - } - else - { - tmp = nullptr; - } - detail::write(fh_buf, fh); - } - - ~data() - { - if(tmp) - boost_asio_handler_alloc_helpers:: - deallocate(tmp, tmp_size, h); - } - }; - - std::shared_ptr d_; - -public: - write_frame_op(write_frame_op&&) = default; - write_frame_op(write_frame_op const&) = default; - - template - write_frame_op(DeducedHandler&& h, - stream& ws, Args&&... args) - : d_(std::make_shared( - std::forward(h), ws, - std::forward(args)...)) - { - (*this)(error_code{}, false); - } - - void operator()() - { - (*this)(error_code{}); - } - - void operator()(error_code ec, std::size_t); - - void operator()(error_code ec, bool again = true); - - friend - void* asio_handler_allocate( - std::size_t size, write_frame_op* op) - { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); - } - - friend - void asio_handler_deallocate( - void* p, std::size_t size, write_frame_op* op) - { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); - } - - friend - bool asio_handler_is_continuation(write_frame_op* op) - { - return op->d_->cont; - } - - template - friend - void asio_handler_invoke(Function&& f, write_frame_op* op) - { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); - } -}; - -template -template -void -stream:: -write_frame_op:: -operator()(error_code ec, std::size_t) -{ - auto& d = *d_; - if(ec) - d.ws.failed_ = true; - (*this)(ec); -} - -template -template -void -stream:: -write_frame_op:: -operator()(error_code ec, bool again) -{ - using boost::asio::buffer_copy; - using boost::asio::mutable_buffers_1; - auto& d = *d_; - d.cont = d.cont || again; - if(ec) - goto upcall; - for(;;) - { - switch(d.state) - { - case 0: - if(d.ws.wr_block_) - { - // suspend - d.state = 3; - d.ws.wr_op_.template emplace< - write_frame_op>(std::move(*this)); - return; - } - if(d.ws.failed_ || d.ws.wr_close_) - { - // call handler - d.state = 99; - d.ws.get_io_service().post( - bind_handler(std::move(*this), - boost::asio::error::operation_aborted)); - return; - } - // fall through - - case 1: - { - if(! d.fh.mask) - { - // send header and entire payload - d.state = 99; - assert(! d.ws.wr_block_); - d.ws.wr_block_ = &d; - boost::asio::async_write(d.ws.stream_, - buffer_cat(d.fh_buf.data(), d.cb), - std::move(*this)); - return; - } - auto const n = - detail::clamp(d.remain, d.tmp_size); - mutable_buffers_1 mb{d.tmp, n}; - buffer_copy(mb, d.cb); - d.cb.consume(n); - d.remain -= n; - detail::mask_inplace(mb, d.key); - // send header and payload - d.state = d.remain > 0 ? 2 : 99; - assert(! d.ws.wr_block_); - d.ws.wr_block_ = &d; - boost::asio::async_write(d.ws.stream_, - buffer_cat(d.fh_buf.data(), - mb), std::move(*this)); - return; - } - - // sent masked payload - case 2: - { - auto const n = - detail::clamp(d.remain, d.tmp_size); - mutable_buffers_1 mb{d.tmp, - static_cast(n)}; - buffer_copy(mb, d.cb); - d.cb.consume(n); - d.remain -= n; - detail::mask_inplace(mb, d.key); - // send payload - if(d.remain == 0) - d.state = 99; - assert(d.ws.wr_block_ == &d); - boost::asio::async_write( - d.ws.stream_, mb, std::move(*this)); - return; - } - - case 3: - d.state = 4; - d.ws.get_io_service().post(bind_handler( - std::move(*this), ec)); - return; - - case 4: - if(d.ws.failed_ || d.ws.wr_close_) - { - // call handler - ec = boost::asio::error::operation_aborted; - goto upcall; - } - d.state = 1; - break; - - case 99: - goto upcall; - } - } -upcall: - if(d.tmp) - { - boost_asio_handler_alloc_helpers:: - deallocate(d.tmp, d.tmp_size, d.h); - d.tmp = nullptr; - } - if(d.ws.wr_block_ == &d) - d.ws.wr_block_ = nullptr; - d.ws.rd_op_.maybe_invoke(); - d.h(ec); -} - -} // websocket -} // beast - -#endif diff --git a/include/beast/websocket/impl/write_op.ipp b/include/beast/websocket/impl/write_op.ipp deleted file mode 100644 index 3aa483611..000000000 --- a/include/beast/websocket/impl/write_op.ipp +++ /dev/null @@ -1,140 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -#ifndef BEAST_WEBSOCKET_IMPL_WRITE_OP_HPP -#define BEAST_WEBSOCKET_IMPL_WRITE_OP_HPP - -#include -#include -#include -#include -#include -#include -#include - -namespace beast { -namespace websocket { - -// write a message -// -template -template -class stream::write_op -{ - using alloc_type = - handler_alloc; - - struct data : op - { - stream& ws; - consuming_buffers cb; - Handler h; - std::size_t remain; - bool cont; - int state = 0; - - template - data(DeducedHandler&& h_, - stream& ws_, Buffers const& bs) - : ws(ws_) - , cb(bs) - , h(std::forward(h_)) - , remain(boost::asio::buffer_size(cb)) - , cont(boost_asio_handler_cont_helpers:: - is_continuation(h)) - { - } - }; - - std::shared_ptr d_; - -public: - write_op(write_op&&) = default; - write_op(write_op const&) = default; - - template - explicit - write_op(DeducedHandler&& h, - stream& ws, Args&&... args) - : d_(std::allocate_shared(alloc_type{h}, - std::forward(h), ws, - std::forward(args)...)) - { - (*this)(error_code{}, false); - } - - void operator()(error_code ec, bool again = true); - - friend - void* asio_handler_allocate( - std::size_t size, write_op* op) - { - return boost_asio_handler_alloc_helpers:: - allocate(size, op->d_->h); - } - - friend - void asio_handler_deallocate( - void* p, std::size_t size, write_op* op) - { - return boost_asio_handler_alloc_helpers:: - deallocate(p, size, op->d_->h); - } - - friend - bool asio_handler_is_continuation(write_op* op) - { - return op->d_->cont; - } - - template - friend - void asio_handler_invoke(Function&& f, write_op* op) - { - return boost_asio_handler_invoke_helpers:: - invoke(f, op->d_->h); - } -}; - -template -template -void -stream:: -write_op:: -operator()(error_code ec, bool again) -{ - auto& d = *d_; - d.cont = d.cont || again; - if(! ec) - { - switch(d.state) - { - case 0: - { - auto const n = std::min( - d.remain, d.ws.wr_frag_size_); - d.remain -= n; - auto const fin = d.remain <= 0; - if(fin) - d.state = 99; - auto const pb = prepare_buffers(n, d.cb); - d.cb.consume(n); - d.ws.async_write_frame(fin, pb, std::move(*this)); - return; - } - - case 99: - break; - } - } - d.h(ec); -} - -} // websocket -} // beast - -#endif diff --git a/include/beast/websocket/option.hpp b/include/beast/websocket/option.hpp index abe22409e..d2864cdd2 100644 --- a/include/beast/websocket/option.hpp +++ b/include/beast/websocket/option.hpp @@ -9,9 +9,10 @@ #define BEAST_WEBSOCKET_OPTION_HPP #include -#include +#include #include #include +#include #include #include #include @@ -19,37 +20,38 @@ namespace beast { namespace websocket { -/** Automatic fragmentation size option. +/** Automatic fragmentation option. - Sets the maximum size of fragments generated when sending messages - on a WebSocket stream. + Determines if outgoing message payloads are broken up into + multiple pieces. - When the automatic fragmentation size is non-zero, messages exceeding - the size will be split into multiple frames no larger than the size. - This setting does not affect frames sent explicitly using - @ref stream::write_frame or @ref stream::async_write_frame. + When the automatic fragmentation size is turned on, outgoing + message payloads are broken up into multiple frames no larger + than the write buffer size. - The default setting is to fragment messages into 16KB frames. + The default setting is to fragment messages. - @note Objects of this type are passed to @ref stream::set_option. + @note Objects of this type are used with + @ref beast::websocket::stream::set_option. @par Example - Setting the automatic fragmentation size option: + Setting the automatic fragmentation option: @code ... websocket::stream stream(ios); - stream.set_option(auto_fragment_size{8192}); + stream.set_option(auto_fragment{true}); @endcode */ #if GENERATING_DOCS -using auto_fragment_size = implementation_defined; +using auto_fragment = implementation_defined; #else -struct auto_fragment_size +struct auto_fragment { - std::size_t value; + bool value; - auto_fragment_size(std::size_t n) - : value(n) + explicit + auto_fragment(bool v) + : value(v) { } }; @@ -76,21 +78,22 @@ struct auto_fragment_size The default setting is no decorator. - @note Objects of this type are passed to @ref stream::set_option. + @note Objects of this type are used with + @ref beast::websocket::stream::set_option. @par Example Setting the decorator. @code struct identity { - template + template void - operator()(http::message& m) + operator()(http::message& m) { if(isRequest) - m.headers.replace("User-Agent", "MyClient"); + m.fields.replace("User-Agent", "MyClient"); else - m.headers.replace("Server", "MyServer"); + m.fields.replace("Server", "MyServer"); } }; ... @@ -125,7 +128,8 @@ decorate(Decorator&& d) The default setting is to close connections after a failed upgrade request. - @note Objects of this type are passed to @ref stream::set_option. + @note Objects of this type are used with + @ref beast::websocket::stream::set_option. @par Example Setting the keep alive option. @@ -142,6 +146,7 @@ struct keep_alive { bool value; + explicit keep_alive(bool v) : value(v) { @@ -149,45 +154,6 @@ struct keep_alive }; #endif -/** Mask buffer size option. - - Sets the size of the buffer allocated when the implementation - must allocate memory to apply the mask to a payload. Only affects - streams operating in the client role, since only clients send - masked frames. Lowering the size of the buffer can decrease the - memory requirements for each connection, while increasing the size - of the buffer can reduce the number of calls made to the next - layer to write masked data. - - The default setting is 4096. The minimum value is 1. - - @note Objects of this type are passed to @ref stream::set_option. - - @par Example - Setting the write buffer size. - @code - ... - websocket::stream ws(ios); - ws.set_option(mask_buffer_size{8192}); - @endcode -*/ -#if GENERATING_DOCS -using mask_buffer_size = implementation_defined; -#else -struct mask_buffer_size -{ - std::size_t value; - - explicit - mask_buffer_size(std::size_t n) - : value(n) - { - if(n == 0) - throw std::domain_error("invalid mask buffer size"); - } -}; -#endif - /** Message type option. This controls the opcode set for outgoing messages. Valid @@ -198,7 +164,8 @@ struct mask_buffer_size The default setting is opcode::text. - @note Objects of this type are passed to @ref stream::set_option. + @note Objects of this type are used with + @ref beast::websocket::stream::set_option. @par Example Setting the message type to binary. @@ -225,11 +192,19 @@ struct message_type }; #endif +namespace detail { + +using pong_cb = std::function; + +} // detail + /** Pong callback option. Sets the callback to be invoked whenever a pong is received - during a call to @ref read, @ref read_frame, @ref async_read, - or @ref async_read_frame. + during a call to @ref beast::websocket::stream::read, + @ref beast::websocket::stream::read_frame, + @ref beast::websocket::stream::async_read, or + @ref beast::websocket::stream::async_read_frame. Unlike completion handlers, the callback will be invoked for each received pong during a call to any synchronous or @@ -247,8 +222,10 @@ struct message_type operation, the callback will be invoked using the same method as that used to invoke the final handler. - @note To remove the pong callback, construct the option with - no parameters: `set_option(pong_callback{})` + @note Objects of this type are used with + @ref beast::websocket::stream::set_option. + To remove the pong callback, construct the option with + no parameters: `set_option(pong_callback{})` */ #if GENERATING_DOCS using pong_callback = implementation_defined; @@ -278,7 +255,8 @@ struct pong_callback The default is no buffering. - @note Objects of this type are passed to @ref stream::set_option. + @note Objects of this type are used with + @ref beast::websocket::stream::set_option. @par Example Setting the read buffer size. @@ -306,13 +284,14 @@ struct read_buffer_size /** Maximum incoming message size option. Sets the largest permissible incoming message size. Message - frame headers indicating a size that would bring the total + frame fields indicating a size that would bring the total message size over this limit will cause a protocol failure. The default setting is 16 megabytes. A value of zero indicates - a limit of `std::numeric_limits::max()`. + a limit of the maximum value of a `std::uint64_t`. - @note Objects of this type are passed to @ref stream::set_option. + @note Objects of this type are used with + @ref beast::websocket::stream::set_option. @par Example Setting the maximum read message size. @@ -337,6 +316,51 @@ struct read_message_max }; #endif +/** Write buffer size option. + + Sets the size of the write buffer used by the implementation to + send frames. The write buffer is needed when masking payload data + in the client role, compressing frames, or auto-fragmenting message + data. + + Lowering the size of the buffer can decrease the memory requirements + for each connection, while increasing the size of the buffer can reduce + the number of calls made to the next layer to write data. + + The default setting is 4096. The minimum value is 8. + + The write buffer size can only be changed when the stream is not + open. Undefined behavior results if the option is modified after a + successful WebSocket handshake. + + @note Objects of this type are used with + @ref beast::websocket::stream::set_option. + + @par Example + Setting the write buffer size. + @code + ... + websocket::stream ws(ios); + ws.set_option(write_buffer_size{8192}); + @endcode +*/ +#if GENERATING_DOCS +using write_buffer_size = implementation_defined; +#else +struct write_buffer_size +{ + std::size_t value; + + explicit + write_buffer_size(std::size_t n) + : value(n) + { + if(n < 8) + throw std::domain_error("write buffer size is too small"); + } +}; +#endif + } // websocket } // beast diff --git a/include/beast/websocket/stream.hpp b/include/beast/websocket/stream.hpp index dcc5f75d0..d5f26fb81 100644 --- a/include/beast/websocket/stream.hpp +++ b/include/beast/websocket/stream.hpp @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include @@ -72,8 +72,8 @@ struct frame_info For asynchronous operations, the type must support the @b `AsyncStream` concept. - @note A stream object must not be destroyed while there are - pending asynchronous operations associated with it. + @note A stream object must not be moved or destroyed while there + are pending asynchronous operations associated with it. @par Concepts @b `AsyncStream`, @@ -168,18 +168,34 @@ public: /// Set the automatic fragment size option void - set_option(auto_fragment_size const& o) + set_option(auto_fragment const& o) { - if(o.value <= 0) - wr_frag_size_ = - std::numeric_limits::max(); - else - wr_frag_size_ = o.value; + wr_autofrag_ = o.value; } - /// Set the decorator used for HTTP messages + /** Set the decorator used for HTTP messages. + + The value for this option is a callable type with two + optional signatures: + + @code + void(request_type&); + + void(response_type&); + @endcode + + If a matching signature is provided, the callable type + will be invoked with the HTTP request or HTTP response + object as appropriate. When a signature is omitted, + a default consisting of the string Beast followed by + the version number is used. + */ void +#if GENERATING_DOCS + set_option(implementation_defined o) +#else set_option(detail::decorator_type o) +#endif { d_ = std::move(o); } @@ -219,12 +235,11 @@ public: rd_msg_max_ = o.value; } - /// Set the size of the mask buffer + /// Set the size of the write buffer void - set_option(mask_buffer_size const& o) + set_option(write_buffer_size const& o) { - mask_buf_size_ = o.value; - stream_.capacity(o.value); + wr_buf_size_ = o.value; } /** Get the io_service associated with the stream. @@ -332,7 +347,7 @@ public: HTTP response is sent indicating the reason and status code (typically 400, "Bad Request"). This counts as a failure. - @throws boost::system::system_error Thrown on failure. + @throws system_error Thrown on failure. */ void accept(); @@ -442,7 +457,7 @@ public: then to received WebSocket frames. The implementation will copy the caller provided data before the function returns. - @throws boost::system::system_error Thrown on failure. + @throws system_error Thrown on failure. */ template void @@ -565,12 +580,12 @@ public: Ownership is not transferred, the implementation will not access this object from other threads. - @throws boost::system::system_error Thrown on failure. + @throws system_error Thrown on failure. */ // VFALCO TODO This should also take a DynamicBuffer with any leftover bytes. - template + template void - accept(http::request_v1 const& request); + accept(http::request const& request); /** Respond to a WebSocket HTTP Upgrade request @@ -600,9 +615,9 @@ public: @param ec Set to indicate what error occurred, if any. */ - template + template void - accept(http::request_v1 const& request, + accept(http::request const& request, error_code& ec); /** Start responding to a WebSocket HTTP Upgrade request. @@ -646,14 +661,14 @@ public: this function. Invocation of the handler will be performed in a manner equivalent to using `boost::asio::io_service::post`. */ - template + template #if GENERATING_DOCS void_or_deduced #else typename async_completion< AcceptHandler, void(error_code)>::result_type #endif - async_accept(http::request_v1 const& request, + async_accept(http::request const& request, AcceptHandler&& handler); /** Send a HTTP WebSocket Upgrade request and receive the response. @@ -680,7 +695,7 @@ public: @param resource The requesting URI, which may not be empty, required by the HTTP protocol. - @throws boost::system::system_error Thrown on failure. + @throws system_error Thrown on failure. @par Example @code @@ -802,13 +817,13 @@ public: @li An error occurs on the stream. - This function is implemented in terms of one or more calls to the - next layer's `write_some` functions. + This function is implemented in terms of one or more calls + to the next layer's `write_some` functions. If the close reason specifies a close code other than - @ref close_code::none, the close frame is sent with the close - code and optional reason string. Otherwise, the close frame - is sent with no payload. + @ref beast::websocket::close_code::none, the close frame is + sent with the close code and optional reason string. Otherwise, + the close frame is sent with no payload. Callers should not attempt to write WebSocket data after initiating the close. Instead, callers should continue @@ -817,7 +832,7 @@ public: @param cr The reason for the close. - @throws boost::system::system_error Thrown on failure. + @throws system_error Thrown on failure. */ void close(close_reason const& cr); @@ -831,13 +846,13 @@ public: @li An error occurs on the stream. - This function is implemented in terms of one or more calls to the - next layer's `write_some` functions. + This function is implemented in terms of one or more calls + to the next layer's `write_some` functions. If the close reason specifies a close code other than - @ref close_code::none, the close frame is sent with the close - code and optional reason string. Otherwise, the close frame - is sent with no payload. + @ref beast::websocket::close_code::none, the close frame is + sent with the close code and optional reason string. Otherwise, + the close frame is sent with no payload. Callers should not attempt to write WebSocket data after initiating the close. Instead, callers should continue @@ -870,9 +885,9 @@ public: @ref stream::async_close) until this operation completes. If the close reason specifies a close code other than - @ref close_code::none, the close frame is sent with the close - code and optional reason string. Otherwise, the close frame - is sent with no payload. + @ref beast::websocket::close_code::none, the close frame is + sent with the close code and optional reason string. Otherwise, + the close frame is sent with no payload. Callers should not attempt to write WebSocket data after initiating the close. Instead, callers should continue @@ -917,7 +932,7 @@ public: @param payload The payload of the ping message, which may be empty. - @throws boost::system::system_error Thrown on failure. + @throws system_error Thrown on failure. */ void ping(ping_data const& payload); @@ -972,14 +987,107 @@ public: this function. Invocation of the handler will be performed in a manner equivalent to using `boost::asio::io_service::post`. */ - template + template #if GENERATING_DOCS void_or_deduced #else typename async_completion< - PingHandler, void(error_code)>::result_type + WriteHandler, void(error_code)>::result_type #endif - async_ping(ping_data const& payload, PingHandler&& handler); + async_ping(ping_data const& payload, WriteHandler&& handler); + + /** Send a WebSocket pong frame. + + This function is used to synchronously send a pong frame on + the stream. The call blocks until one of the following is true: + + @li The pong frame finishes sending. + + @li An error occurs on the stream. + + This function is implemented in terms of one or more calls to the + next layer's `write_some` functions. + + The WebSocket protocol allows pong frames to be sent from either + end at any time. It is not necessary to first receive a ping in + order to send a pong. The remote peer may use the receipt of a + pong frame as an indication that the connection is not dead. + + @param payload The payload of the pong message, which may be empty. + + @throws system_error Thrown on failure. + */ + void + pong(ping_data const& payload); + + /** Send a WebSocket pong frame. + + This function is used to synchronously send a pong frame on + the stream. The call blocks until one of the following is true: + + @li The pong frame finishes sending. + + @li An error occurs on the stream. + + This function is implemented in terms of one or more calls to the + next layer's `write_some` functions. + + The WebSocket protocol allows pong frames to be sent from either + end at any time. It is not necessary to first receive a ping in + order to send a pong. The remote peer may use the receipt of a + pong frame as an indication that the connection is not dead. + + @param payload The payload of the pong message, which may be empty. + + @param ec Set to indicate what error occurred, if any. + */ + void + pong(ping_data const& payload, error_code& ec); + + /** Start an asynchronous operation to send a WebSocket pong frame. + + This function is used to asynchronously send a pong frame to + the stream. The function call always returns immediately. The + asynchronous operation will continue until one of the following + is true: + + @li The entire pong frame is sent. + + @li An error occurs on the stream. + + This operation is implemented in terms of one or more calls to the + next layer's `async_write_some` functions, and is known as a + composed operation. The program must ensure that the + stream performs no other writes until this operation completes. + + The WebSocket protocol allows pong frames to be sent from either + end at any time. It is not necessary to first receive a ping in + order to send a pong. The remote peer may use the receipt of a + pong frame as an indication that the connection is not dead. + + @param payload The payload of the pong message, which may be empty. + + @param handler The handler to be called when the read operation + completes. Copies will be made of the handler as required. The + function signature of the handler must be: + @code + void handler( + error_code const& error // Result of operation + ); + @endcode + Regardless of whether the asynchronous operation completes + immediately or not, the handler will not be invoked from within + this function. Invocation of the handler will be performed in a + manner equivalent to using `boost::asio::io_service::post`. + */ + template +#if GENERATING_DOCS + void_or_deduced +#else + typename async_completion< + WriteHandler, void(error_code)>::result_type +#endif + async_pong(ping_data const& payload, WriteHandler&& handler); /** Read a message from the stream. @@ -998,7 +1106,8 @@ public: hold all the message payload bytes (which may be zero in length). Control frames encountered while reading frame or message data - are handled automatically. Pings are replied to, pongs are noted, + are handled automatically. Pings are replied to automatically, + pongs are routed to the pong callback if the option is set, and close frames initiate the WebSocket close procedure. When a close frame is received, this call will eventually return @ref error::closed. Because of the need to handle control frames, @@ -1010,7 +1119,7 @@ public: @param dynabuf A dynamic buffer to hold the message data after any masking or decompression has been applied. - @throws boost::system::system_error Thrown on failure. + @throws system_error Thrown on failure. */ template void @@ -1033,7 +1142,8 @@ public: hold all the message payload bytes (which may be zero in length). Control frames encountered while reading frame or message data - are handled automatically. Pings are replied to, pongs are noted, + are handled automatically. Pings are replied to automatically, + pongs are routed to the pong callback if the option is set, and close frames initiate the WebSocket close procedure. When a close frame is received, this call will eventually return @ref error::closed. Because of the need to handle control frames, @@ -1073,10 +1183,10 @@ public: hold all the message payload bytes (which may be zero in length). Control frames encountered while reading frame or message data - are handled automatically. Pings are replied to, pongs cause - an outstanding call to `async_ping` to complete, and close - frames initiate the WebSocket close procedure. When a close - frame is received, this call will eventually return + are handled automatically. Pings are replied to automatically, + pongs are routed to the pong callback if the option is set, + and close frames initiate the WebSocket close procedure. When a + close frame is received, this call will eventually return @ref error::closed. Because of the need to handle control frames, these read operations can cause writes to take place. Despite this, calls to `async_read` and `async_read_frame` @@ -1132,7 +1242,8 @@ public: fi.fin == true, and zero bytes placed into the stream buffer. Control frames encountered while reading frame or message data - are handled automatically. Pings are replied to, pongs are noted, + are handled automatically. Pings are replied to automatically, + pongs are routed to the pong callback if the option is set, and close frames initiate the WebSocket close procedure. When a close frame is received, this call will eventually return @ref error::closed. Because of the need to handle control frames, @@ -1143,7 +1254,7 @@ public: @param dynabuf A dynamic buffer to hold the message data after any masking or decompression has been applied. - @throws boost::system::system_error Thrown on failure. + @throws system_error Thrown on failure. */ template void @@ -1170,7 +1281,8 @@ public: fi.fin == true, and zero bytes placed into the stream buffer. Control frames encountered while reading frame or message data - are handled automatically. Pings are replied to, pongs are noted, + are handled automatically. Pings are replied to automatically, + pongs are routed to the pong callback if the option is set, and close frames initiate the WebSocket close procedure. When a close frame is received, this call will eventually return @ref error::closed. Because of the need to handle control frames, @@ -1213,7 +1325,8 @@ public: the stream buffer. Control frames encountered while reading frame or message data - are handled automatically. Pings are replied to, pongs are noted, + are handled automatically. Pings are replied to automatically, + pongs are routed to the pong callback if the option is set, and close frames initiate the WebSocket close procedure. When a close frame is received, this call will eventually return @ref error::closed. Because of the need to handle control frames, @@ -1268,7 +1381,7 @@ public: The current setting of the @ref message_type option controls whether the message opcode is set to text or binary. If the - @ref auto_fragment_size option is set, the message will be split + @ref auto_fragment option is set, the message will be split into one or more frames as necessary. The actual payload contents sent may be transformed as per the WebSocket protocol settings. @@ -1279,7 +1392,7 @@ public: the memory locations pointed to by buffers remains valid until the completion handler is called. - @throws boost::system::system_error Thrown on failure. + @throws system_error Thrown on failure. @note This function always sends an entire message. To send a message in fragments, use @ref write_frame. @@ -1303,7 +1416,7 @@ public: The current setting of the @ref message_type option controls whether the message opcode is set to text or binary. If the - @ref auto_fragment_size option is set, the message will be split + @ref auto_fragment option is set, the message will be split into one or more frames as necessary. The actual payload contents sent may be transformed as per the WebSocket protocol settings. @@ -1316,7 +1429,7 @@ public: @param ec Set to indicate what error occurred, if any. - @throws boost::system::system_error Thrown on failure. + @throws system_error Thrown on failure. @note This function always sends an entire message. To send a message in fragments, use @ref write_frame. @@ -1345,7 +1458,7 @@ public: The current setting of the @ref message_type option controls whether the message opcode is set to text or binary. If the - @ref auto_fragment_size option is set, the message will be split + @ref auto_fragment option is set, the message will be split into one or more frames as necessary. The actual payload contents sent may be transformed as per the WebSocket protocol settings. @@ -1379,12 +1492,15 @@ public: async_write(ConstBufferSequence const& buffers, WriteHandler&& handler); - /** Send a message frame on the stream. + /** Write partial message data on the stream. - This function is used to write a frame to the stream. The - call will block until one of the following conditions is true: + This function is used to write some or all of a message's + payload to the stream. The call will block until one of the + following conditions is true: - @li The entire frame is sent. + @li A frame is sent. + + @li Message data is transferred to the write buffer. @li An error occurs. @@ -1398,27 +1514,30 @@ public: @param fin `true` if this is the last frame in the message. - @param buffers One or more buffers containing the frame's - payload data. + @param buffers The input buffer sequence holding the data to write. - @throws boost::system::system_error Thrown on failure. + @return The number of bytes consumed in the input buffers. + + @throws system_error Thrown on failure. */ template void write_frame(bool fin, ConstBufferSequence const& buffers); - /** Send a message frame on the stream. + /** Write partial message data on the stream. - This function is used to write a frame to the stream. The - call will block until one of the following conditions is true: + This function is used to write some or all of a message's + payload to the stream. The call will block until one of the + following conditions is true: - @li The entire frame is sent. + @li A frame is sent. + + @li Message data is transferred to the write buffer. @li An error occurs. This operation is implemented in terms of one or more calls - to the stream's `write_some` function. The actual payload sent - may be transformed as per the WebSocket protocol settings. + to the stream's `write_some` function. If this is the beginning of a new message, the message opcode will be set to text or binary as per the current setting of @@ -1427,10 +1546,11 @@ public: @param fin `true` if this is the last frame in the message. - @param buffers One or more buffers containing the frame's - payload data. + @param buffers The input buffer sequence holding the data to write. @param ec Set to indicate what error occurred, if any. + + @return The number of bytes consumed in the input buffers. */ template void @@ -1475,7 +1595,7 @@ public: Copies will be made of the handler as required. The equivalent function signature of the handler must be: @code void handler( - boost::system::error_code const& error // result of operation + error_code const& error // result of operation ); @endcode */ template @@ -1502,18 +1622,18 @@ private: void reset(); - http::request_v1 + http::request build_request(boost::string_ref const& host, boost::string_ref const& resource, std::string& key); - template - http::response_v1 - build_response(http::request_v1 const& req); + template + http::response + build_response(http::request const& req); - template + template void - do_response(http::response_v1 const& resp, + do_response(http::response const& resp, boost::string_ref const& key, error_code& ec); void @@ -1524,6 +1644,12 @@ private: } // websocket } // beast +#include +#include +#include +#include +#include #include +#include #endif diff --git a/include/beast/websocket/teardown.hpp b/include/beast/websocket/teardown.hpp index d3ffd2c8a..3682a18f8 100644 --- a/include/beast/websocket/teardown.hpp +++ b/include/beast/websocket/teardown.hpp @@ -13,13 +13,13 @@ #include namespace beast { - namespace websocket { -/** Tag type used to find teardown and async_teardown overloads +/** Tag type used to find @ref beast::websocket::teardown and @ref beast::websocket::async_teardown overloads - Overloads of @ref teardown and @async_teardown for user defined - types must take a value of type @ref teardown_tag in the first + Overloads of @ref beast::websocket::teardown and + @ref beast::websocket::async_teardown for user defined types + must take a value of type @ref teardown_tag in the first argument in order to be found by the implementation. */ struct teardown_tag {}; @@ -178,7 +178,6 @@ async_teardown(teardown_tag, boost::asio::ip::tcp::socket& socket, TeardownHandler&& handler); } // websocket - } // beast #include diff --git a/include/beast/zlib.hpp b/include/beast/zlib.hpp new file mode 100644 index 000000000..c2173d127 --- /dev/null +++ b/include/beast/zlib.hpp @@ -0,0 +1,14 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_ZLIB_HPP +#define BEAST_ZLIB_HPP + +#include +#include + +#endif diff --git a/include/beast/zlib/deflate_stream.hpp b/include/beast/zlib/deflate_stream.hpp new file mode 100644 index 000000000..06256d2eb --- /dev/null +++ b/include/beast/zlib/deflate_stream.hpp @@ -0,0 +1,398 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This is a derivative work based on Zlib, copyright below: +/* + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef BEAST_ZLIB_DEFLATE_STREAM_HPP +#define BEAST_ZLIB_DEFLATE_STREAM_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace zlib { + +/** Raw deflate compressor. + + This is a port of zlib's "deflate" functionality to C++. +*/ +class deflate_stream + : private detail::deflate_stream +{ +public: + /** Construct a default deflate stream. + + Upon construction, the stream settings will be set + to these default values: + + @li `level = 6` + + @li `windowBits = 15` + + @li `memLevel = 8` + + @li `strategy = Strategy::normal` + + Although the stream is ready to be used immediately + after construction, any required internal buffers are + not dynamically allocated until needed. + */ + deflate_stream() + { + reset(6, 15, DEF_MEM_LEVEL, Strategy::normal); + } + + /** Reset the stream and compression settings. + + This function initializes the stream to the specified + compression settings. + + Although the stream is ready to be used immediately + after a reset, any required internal buffers are not + dynamically allocated until needed. + + @note Any unprocessed input or pending output from + previous calls are discarded. + */ + void + reset( + int level, + int windowBits, + int memLevel, + Strategy strategy) + { + doReset(level, windowBits, memLevel, strategy); + } + + /** Reset the stream without deallocating memory. + + This function performs the equivalent of calling `clear` + followed by `reset` with the same compression settings, + without deallocating the internal buffers. + + @note Any unprocessed input or pending output from + previous calls are discarded. + */ + void + reset() + { + doReset(); + } + + /** Clear the stream. + + This function resets the stream and frees all dynamically + allocated internal buffers. The compression settings are + left unchanged. + + @note Any unprocessed input or pending output from + previous calls are discarded. + */ + void + clear() + { + doClear(); + } + + /** Returns the upper limit on the size of a compressed block. + + This function makes a conservative estimate of the maximum number + of bytes needed to store the result of compressing a block of + data based on the current compression level and strategy. + + @param bytes The size of the uncompressed data. + + @return The maximum number of resulting compressed bytes. + */ + std::size_t + upper_bound(std::size_t sourceLen) const + { + return doUpperBound(sourceLen); + } + + /** Fine tune internal compression parameters. + + Compression parameters should only be tuned by someone who + understands the algorithm used by zlib's deflate for searching + for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit + for their specific input data. Read the deflate.c source code + (ZLib) for the meaning of the max_lazy, good_length, nice_length, + and max_chain parameters. + */ + void + tune( + int good_length, + int max_lazy, + int nice_length, + int max_chain) + { + doTune(good_length, max_lazy, nice_length, max_chain); + } + + /** Compress input and write output. + + This function compresses as much data as possible, and stops when + the input buffer becomes empty or the output buffer becomes full. + It may introduce some output latency (reading input without + producing any output) except when forced to flush. + + In each call, one or both of these actions are performed: + + @li Compress more input starting at `zs.next_in` and update + `zs.next_in` and `zs.avail_in` accordingly. If not all + input can be processed (because there is not enough room in + the output buffer), `zs.next_in` and `zs.avail_in` are updated + and processing will resume at this point for the next call. + + @li Provide more output starting at `zs.next_out` and update + `zs.next_out` and `zs.avail_out` accordingly. This action is + forced if the parameter flush is not `Flush::none`. Forcing + flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call, the application must ensure that at least one + of the actions is possible, by providing more input and/or + consuming more output, and updating `zs.avail_in` or `zs.avail_out` + accordingly; `zs.avail_out` should never be zero before the call. + The application can consume the compressed output when it wants, + for example when the output buffer is full (`zs.avail_out == 0`), + or after each call of `write`. If `write` returns no error + with zero `zs.avail_out`, it must be called again after making + room in the output buffer because there might be more output + pending. + + Normally the parameter flush is set to `Flush::none`, which allows + deflate to decide how much data to accumulate before producing + output, in order to maximize compression. + + If the parameter flush is set to `Flush::sync`, all pending output + is flushed to the output buffer and the output is aligned on a + byte boundary, so that the decompressor can get all input data + available so far. In particular `zs.avail_in` is zero after the + call if enough output space has been provided before the call. + Flushing may degrade compression for some compression algorithms + and so it should be used only when necessary. This completes the + current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed + by the four bytes `{ 0x00, 0x00 0xff 0xff }`. + + If flush is set to `Flush::partial`, all pending output is flushed + to the output buffer, but the output is not aligned to a byte + boundary. All of the input data so far will be available to the + decompressor, as for Z_SYNC_FLUSH. This completes the current + deflate block and follows it with an empty fixed codes block that + is 10 bits long. This assures that enough bytes are output in order + for the decompressor to finish the block before the empty fixed + code block. + + If flush is set to `Flush::block`, a deflate block is completed + and emitted, as for `Flush::sync`, but the output is not aligned + on a byte boundary, and up to seven bits of the current block are + held to be written as the next byte after the next deflate block + is completed. In this case, the decompressor may not be provided + enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait + for the next block to be emitted. This is for advanced applications + that need to control the emission of deflate blocks. + + If flush is set to `Flush::full`, all output is flushed as with + `Flush::sync`, and the compression state is reset so that + decompression can restart from this point if previous compressed + data has been damaged or if random access is desired. Using + `Flush::full` too often can seriously degrade compression. + + If `write` returns with `zs.avail_out == 0`, this function must + be called again with the same value of the flush parameter and + more output space (updated `zs.avail_out`), until the flush is + complete (`write` returns with non-zero `zs.avail_out`). In the + case of a `Flush::full`or `Flush::sync`, make sure that + `zs.avail_out` is greater than six to avoid repeated flush markers + due to `zs.avail_out == 0` on return. + + If the parameter flush is set to `Flush::finish`, pending input + is processed, pending output is flushed and deflate returns the + error `error::end_of_stream` if there was enough output space; + if deflate returns with no error, this function must be called + again with `Flush::finish` and more output space (updated + `zs.avail_out`) but no more input data, until it returns the + error `error::end_of_stream` or another error. After `write` has + returned the `error::end_of_stream` error, the only possible + operations on the stream are to reset or destroy. + + `Flush::finish` can be used immediately after initialization + if all the compression is to be done in a single step. In this + case, `zs.avail_out` must be at least value returned by + `upper_bound` (see below). Then `write` is guaranteed to return + the `error::end_of_stream` error. If not enough output space + is provided, deflate will not return `error::end_of_stream`, + and it must be called again as described above. + + `write` returns no error if some progress has been made (more + input processed or more output produced), `error::end_of_stream` + if all input has been consumed and all output has been produced + (only when flush is set to `Flush::finish`), `error::stream_error` + if the stream state was inconsistent (for example if `zs.next_in` + or `zs.next_out` was `nullptr`), `error::need_buffers` if no + progress is possible (for example `zs.avail_in` or `zs.avail_out` + was zero). Note that `error::need_buffers` is not fatal, and + `write` can be called again with more input and more output space + to continue compressing. + */ + void + write( + z_params& zs, + Flush flush, + error_code& ec) + { + doWrite(zs, flush, ec); + } + + /** Update the compression level and strategy. + + This function dynamically updates the compression level and + compression strategy. The interpretation of level and strategy + is as in @ref reset. This can be used to switch between compression + and straight copy of the input data, or to switch to a different kind + of input data requiring a different strategy. If the compression level + is changed, the input available so far is compressed with the old level + (and may be flushed); the new level will take effect only at the next + call of @ref write. + + Before the call of `params`, the stream state must be set as for a + call of @ref write, since the currently available input may have to be + compressed and flushed. In particular, `zs.avail_out` must be non-zero. + + @return `Z_OK` if success, `Z_STREAM_ERROR` if the source stream state + was inconsistent or if a parameter was invalid, `error::need_buffers` + if `zs.avail_out` was zero. + */ + void + params( + z_params& zs, + int level, + Strategy strategy, + error_code& ec) + { + doParams(zs, level, strategy, ec); + } + + /** Return bits pending in the output. + + This function returns the number of bytes and bits of output + that have been generated, but not yet provided in the available + output. The bytes not provided would be due to the available + output space having being consumed. The number of bits of output + not provided are between 0 and 7, where they await more bits to + join them in order to fill out a full byte. If pending or bits + are `nullptr`, then those values are not set. + + @return `Z_OK` if success, or `Z_STREAM_ERROR` if the source + stream state was inconsistent. + */ + void + pending(unsigned *value, int *bits) + { + doPending(value, bits); + } + + /** Insert bits into the compressed output stream. + + This function inserts bits in the deflate output stream. The + intent is that this function is used to start off the deflate + output with the bits leftover from a previous deflate stream when + appending to it. As such, this function can only be used for raw + deflate, and must be used before the first `write` call after an + initialization. `bits` must be less than or equal to 16, and that + many of the least significant bits of `value` will be inserted in + the output. + + @return `error::need_buffers` if there was not enough room in + the internal buffer to insert the bits. + */ + void + prime(int bits, int value, error_code& ec) + { + return doPrime(bits, value, ec); + } +}; + +/** Returns the upper limit on the size of a compressed block. + + This function makes a conservative estimate of the maximum number + of bytes needed to store the result of compressing a block of + data. + + @param bytes The size of the uncompressed data. + + @return The maximum number of resulting compressed bytes. +*/ +std::size_t +deflate_upper_bound(std::size_t bytes); + +/* For the default windowBits of 15 and memLevel of 8, this function returns + a close to exact, as well as small, upper bound on the compressed size. + They are coded as constants here for a reason--if the #define's are + changed, then this function needs to be changed as well. The return + value for 15 and 8 only works for those exact settings. + + For any setting other than those defaults for windowBits and memLevel, + the value returned is a conservative worst case for the maximum expansion + resulting from using fixed blocks instead of stored blocks, which deflate + can emit on compressed data for some combinations of the parameters. + + This function could be more sophisticated to provide closer upper bounds for + every combination of windowBits and memLevel. But even the conservative + upper bound of about 14% expansion does not seem onerous for output buffer + allocation. +*/ +inline +std::size_t +deflate_upper_bound(std::size_t bytes) +{ + return bytes + + ((bytes + 7) >> 3) + + ((bytes + 63) >> 6) + 5 + + 6; +} + +} // zlib +} // beast + +#endif diff --git a/include/beast/zlib/detail/bitstream.hpp b/include/beast/zlib/detail/bitstream.hpp new file mode 100644 index 000000000..9c470cf89 --- /dev/null +++ b/include/beast/zlib/detail/bitstream.hpp @@ -0,0 +1,203 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This is a derivative work based on Zlib, copyright below: +/* + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef BEAST_ZLIB_DETAIL_BITSTREAM_HPP +#define BEAST_ZLIB_DETAIL_BITSTREAM_HPP + +#include +#include +#include + +namespace beast { +namespace zlib { +namespace detail { + +class bitstream +{ + using value_type = std::uint32_t; + + value_type v_ = 0; + unsigned n_ = 0; + +public: + // returns the number of bits in the reservoir + unsigned + size() const + { + return n_; + } + + // discard n bits + void + drop(std::size_t n) + { + BOOST_ASSERT(n <= n_); + n_ -= static_cast(n); + v_ >>= n; + } + + // flush everything + void + flush() + { + n_ = 0; + v_ = 0; + } + + // flush to the next byte boundary + void + flush_byte() + { + drop(n_ % 8); + } + + // ensure at least n bits + template + bool + fill(std::size_t n, FwdIt& first, FwdIt const& last); + + // fill 8 bits, unchecked + template + void + fill_8(FwdIt& it); + + // fill 16 bits, unchecked + template + void + fill_16(FwdIt& it); + + // return n bits + template + void + peek(Unsigned& value, std::size_t n); + + // return everything in the reservoir + value_type + peek_fast() const + { + return v_; + } + + // return n bits, and consume + template + void + read(Unsigned& value, std::size_t n); + + // rewind by the number of whole bytes stored (unchecked) + template + void + rewind(BidirIt& it); +}; + +template +inline +bool +bitstream:: +fill(std::size_t n, FwdIt& first, FwdIt const& last) +{ + while(n_ < n) + { + if(first == last) + return false; + v_ += static_cast(*first++) << n_; + n_ += 8; + } + return true; +} + +template +inline +void +bitstream:: +fill_8(FwdIt& it) +{ + v_ += static_cast(*it++) << n_; + n_ += 8; +} + +template +inline +void +bitstream:: +fill_16(FwdIt& it) +{ + v_ += static_cast(*it++) << n_; + n_ += 8; + v_ += static_cast(*it++) << n_; + n_ += 8; +} + +template +inline +void +bitstream:: +peek(Unsigned& value, std::size_t n) +{ + BOOST_ASSERT(n <= sizeof(value)*8); + BOOST_ASSERT(n <= n_); + value = static_cast( + v_ & ((1ULL << n) - 1)); +} + +template +inline +void +bitstream:: +read(Unsigned& value, std::size_t n) +{ + BOOST_ASSERT(n < sizeof(v_)*8); + BOOST_ASSERT(n <= n_); + value = static_cast( + v_ & ((1ULL << n) - 1)); + v_ >>= n; + n_ -= static_cast(n); +} + +template +inline +void +bitstream:: +rewind(BidirIt& it) +{ + auto len = n_ >> 3; + it = std::prev(it, len); + n_ &= 7; + v_ &= (1U << n_) - 1; +} + +} // detail +} // zlib +} // beast + +#endif diff --git a/include/beast/zlib/detail/deflate_stream.hpp b/include/beast/zlib/detail/deflate_stream.hpp new file mode 100644 index 000000000..7b367d3e4 --- /dev/null +++ b/include/beast/zlib/detail/deflate_stream.hpp @@ -0,0 +1,2979 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This is a derivative work based on Zlib, copyright below: +/* + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef BEAST_ZLIB_DETAIL_DEFLATE_STREAM_HPP +#define BEAST_ZLIB_DETAIL_DEFLATE_STREAM_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace zlib { +namespace detail { + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://tools.ietf.org/html/rfc1951 + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +class deflate_stream +{ +protected: + // Upper limit on code length + static std::uint8_t constexpr maxBits = 15; + + // Number of length codes, not counting the special END_BLOCK code + static std::uint16_t constexpr lengthCodes = 29; + + // Number of literal bytes 0..255 + static std::uint16_t constexpr literals = 256; + + // Number of Literal or Length codes, including the END_BLOCK code + static std::uint16_t constexpr lCodes = literals + 1 + lengthCodes; + + // Number of distance code lengths + static std::uint16_t constexpr dCodes = 30; + + // Number of codes used to transfer the bit lengths + static std::uint16_t constexpr blCodes = 19; + + // Number of distance codes + static std::uint16_t constexpr distCodeLen = 512; + + // Size limit on bit length codes + static std::uint8_t constexpr maxBlBits= 7; + + static std::uint16_t constexpr minMatch = 3; + static std::uint16_t constexpr maxMatch = 258; + + // Can't change minMatch without also changing code, see original zlib + static_assert(minMatch==3, ""); + + // end of block literal code + static std::uint16_t constexpr END_BLOCK = 256; + + // repeat previous bit length 3-6 times (2 bits of repeat count) + static std::uint8_t constexpr REP_3_6 = 16; + + // repeat a zero length 3-10 times (3 bits of repeat count) + static std::uint8_t constexpr REPZ_3_10 = 17; + + // repeat a zero length 11-138 times (7 bits of repeat count) + static std::uint8_t constexpr REPZ_11_138 = 18; + + // The three kinds of block type + static std::uint8_t constexpr STORED_BLOCK = 0; + static std::uint8_t constexpr STATIC_TREES = 1; + static std::uint8_t constexpr DYN_TREES = 2; + + // Maximum value for memLevel in deflateInit2 + static std::uint8_t constexpr MAX_MEM_LEVEL = 9; + + // Default memLevel + static std::uint8_t constexpr DEF_MEM_LEVEL = MAX_MEM_LEVEL; + + /* Note: the deflate() code requires max_lazy >= minMatch and max_chain >= 4 + For deflate_fast() (levels <= 3) good is ignored and lazy has a different + meaning. + */ + + // maximum heap size + static std::uint16_t constexpr HEAP_SIZE = 2 * lCodes + 1; + + // size of bit buffer in bi_buf + static std::uint8_t constexpr Buf_size = 16; + + // Matches of length 3 are discarded if their distance exceeds kTooFar + static std::size_t constexpr kTooFar = 4096; + + /* Minimum amount of lookahead, except at the end of the input file. + See deflate.c for comments about the minMatch+1. + */ + static std::size_t constexpr kMinLookahead = maxMatch + minMatch+1; + + /* Number of bytes after end of data in window to initialize in order + to avoid memory checker errors from longest match routines + */ + static std::size_t constexpr kWinInit = maxMatch; + + // Describes a single value and its code string. + struct ct_data + { + std::uint16_t fc; // frequency count or bit string + std::uint16_t dl; // parent node in tree or length of bit string + + bool + operator==(ct_data const& rhs) const + { + return fc == rhs.fc && dl == rhs.dl; + } + }; + + struct static_desc + { + ct_data const* static_tree;// static tree or NULL + std::uint8_t const* extra_bits; // extra bits for each code or NULL + std::uint16_t extra_base; // base index for extra_bits + std::uint16_t elems; // max number of elements in the tree + std::uint8_t max_length; // max bit length for the codes + }; + + struct lut_type + { + // Number of extra bits for each length code + std::uint8_t const extra_lbits[lengthCodes] = { + 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0 + }; + + // Number of extra bits for each distance code + std::uint8_t const extra_dbits[dCodes] = { + 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13 + }; + + // Number of extra bits for each bit length code + std::uint8_t const extra_blbits[blCodes] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7 + }; + + // The lengths of the bit length codes are sent in order + // of decreasing probability, to avoid transmitting the + // lengths for unused bit length codes. + std::uint8_t const bl_order[blCodes] = { + 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 + }; + + ct_data ltree[lCodes + 2]; + + ct_data dtree[dCodes]; + + // Distance codes. The first 256 values correspond to the distances + // 3 .. 258, the last 256 values correspond to the top 8 bits of + // the 15 bit distances. + std::uint8_t dist_code[distCodeLen]; + + std::uint8_t length_code[maxMatch-minMatch+1]; + + std::uint8_t base_length[lengthCodes]; + + std::uint16_t base_dist[dCodes]; + + static_desc l_desc = { + ltree, extra_lbits, literals+1, lCodes, maxBits + }; + + static_desc d_desc = { + dtree, extra_dbits, 0, dCodes, maxBits + }; + + static_desc bl_desc = + { + nullptr, extra_blbits, 0, blCodes, maxBlBits + }; + }; + + struct tree_desc + { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_desc const* stat_desc; /* the corresponding static tree */ + }; + + enum block_state + { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ + }; + + // VFALCO This might not be needed, e.g. for zip/gzip + enum StreamStatus + { + EXTRA_STATE = 69, + NAME_STATE = 73, + COMMENT_STATE = 91, + HCRC_STATE = 103, + BUSY_STATE = 113, + FINISH_STATE = 666 + }; + + /* A std::uint16_t is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + using IPos = unsigned; + + using self = deflate_stream; + typedef block_state(self::*compress_func)(z_params& zs, Flush flush); + + //-------------------------------------------------------------------------- + + lut_type const& lut_; + + bool inited_ = false; + std::size_t buf_size_; + std::unique_ptr buf_; + + int status_; // as the name implies + Byte* pending_buf_; // output still pending + std::uint32_t + pending_buf_size_; // size of pending_buf + Byte* pending_out_; // next pending byte to output to the stream + uInt pending_; // nb of bytes in the pending buffer + boost::optional + last_flush_; // value of flush param for previous deflate call + + uInt w_size_; // LZ77 window size (32K by default) + uInt w_bits_; // log2(w_size) (8..16) + uInt w_mask_; // w_size - 1 + + /* Sliding window. Input bytes are read into the second half of the window, + and move to the first half later to keep a dictionary of at least wSize + bytes. With this organization, matches are limited to a distance of + wSize-maxMatch bytes, but this ensures that IO is always + performed with a length multiple of the block size. Also, it limits + the window size to 64K. + To do: use the user input buffer as sliding window. + */ + Byte *window_ = nullptr; + + /* Actual size of window: 2*wSize, except when the user input buffer + is directly used as sliding window. + */ + std::uint32_t window_size_; + + /* Link to older string with same hash index. To limit the size of this + array to 64K, this link is maintained only for the last 32K strings. + An index in this array is thus a window index modulo 32K. + */ + std::uint16_t* prev_; + + std::uint16_t* head_; // Heads of the hash chains or 0 + + uInt ins_h_; // hash index of string to be inserted + uInt hash_size_; // number of elements in hash table + uInt hash_bits_; // log2(hash_size) + uInt hash_mask_; // hash_size-1 + + /* Number of bits by which ins_h must be shifted at each input + step. It must be such that after minMatch steps, + the oldest byte no longer takes part in the hash key, that is: + hash_shift * minMatch >= hash_bits + */ + uInt hash_shift_; + + /* Window position at the beginning of the current output block. + Gets negative when the window is moved backwards. + */ + long block_start_; + + uInt match_length_; // length of best match + IPos prev_match_; // previous match + int match_available_; // set if previous match exists + uInt strstart_; // start of string to insert + uInt match_start_; // start of matching string + uInt lookahead_; // number of valid bytes ahead in window + + /* Length of the best match at previous step. Matches not greater + than this are discarded. This is used in the lazy match evaluation. + */ + uInt prev_length_; + + /* To speed up deflation, hash chains are never searched beyond + this length. A higher limit improves compression ratio but + degrades the speed. + */ + uInt max_chain_length_; + + /* Attempt to find a better match only when the current match is strictly + smaller than this value. This mechanism is used only for compression + levels >= 4. + + OR Insert new strings in the hash table only if the match length is not + greater than this length. This saves time but degrades compression. + used only for compression levels <= 3. + */ + uInt max_lazy_match_; + + int level_; // compression level (1..9) + Strategy strategy_; // favor or force Huffman coding + + // Use a faster search when the previous match is longer than this + uInt good_match_; + + int nice_match_; // Stop searching when current match exceeds this + + ct_data dyn_ltree_[ + HEAP_SIZE]; // literal and length tree + ct_data dyn_dtree_[ + 2*dCodes+1]; // distance tree + ct_data bl_tree_[ + 2*blCodes+1]; // Huffman tree for bit lengths + + tree_desc l_desc_; // desc. for literal tree + tree_desc d_desc_; // desc. for distance tree + tree_desc bl_desc_; // desc. for bit length tree + + // number of codes at each bit length for an optimal tree + std::uint16_t bl_count_[maxBits+1]; + + // Index within the heap array of least frequent node in the Huffman tree + static std::size_t constexpr kSmallest = 1; + + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. + heap[0] is not used. The same heap array is used to build all trees. + */ + + int heap_[2*lCodes+1]; // heap used to build the Huffman trees + int heap_len_; // number of elements in the heap + int heap_max_; // element of largest frequency + + // Depth of each subtree used as tie breaker for trees of equal frequency + std::uint8_t depth_[2*lCodes+1]; + + std::uint8_t *l_buf_; // buffer for literals or lengths + + /* Size of match buffer for literals/lengths. + There are 4 reasons for limiting lit_bufsize to 64K: + - frequencies can be kept in 16 bit counters + - if compression is not successful for the first block, all input + data is still in the window so we can still emit a stored block even + when input comes from standard input. (This can also be done for + all blocks if lit_bufsize is not greater than 32K.) + - if compression is not successful for a file smaller than 64K, we can + even emit a stored file instead of a stored block (saving 5 bytes). + This is applicable only for zip (not gzip or zlib). + - creating new Huffman trees less frequently may not provide fast + adaptation to changes in the input data statistics. (Take for + example a binary file with poorly compressible code followed by + a highly compressible string table.) Smaller buffer sizes give + fast adaptation but have of course the overhead of transmitting + trees more frequently. + - I can't count above 4 + */ + uInt lit_bufsize_; + uInt last_lit_; // running index in l_buf_ + + /* Buffer for distances. To simplify the code, d_buf_ and l_buf_ + have the same number of elements. To use different lengths, an + extra flag array would be necessary. + */ + std::uint16_t* d_buf_; + + std::uint32_t opt_len_; // bit length of current block with optimal trees + std::uint32_t static_len_; // bit length of current block with static trees + uInt matches_; // number of string matches in current block + uInt insert_; // bytes at end of window left to insert + + /* Output buffer. + Bits are inserted starting at the bottom (least significant bits). + */ + std::uint16_t bi_buf_; + + /* Number of valid bits in bi_buf._ All bits above the last valid + bit are always zero. + */ + int bi_valid_; + + /* High water mark offset in window for initialized bytes -- bytes + above this are set to zero in order to avoid memory check warnings + when longest match routines access bytes past the input. This is + then updated to the new high water mark. + */ + std::uint32_t high_water_; + + //-------------------------------------------------------------------------- + + deflate_stream() + : lut_(get_lut()) + { + } + + /* In order to simplify the code, particularly on 16 bit machines, match + distances are limited to MAX_DIST instead of WSIZE. + */ + std::size_t + max_dist() const + { + return w_size_ - kMinLookahead; + } + + void + put_byte(std::uint8_t c) + { + pending_buf_[pending_++] = c; + } + + void + put_short(std::uint16_t w) + { + put_byte(w & 0xff); + put_byte(w >> 8); + } + + /* Send a value on a given number of bits. + IN assertion: length <= 16 and value fits in length bits. + */ + void + send_bits(int value, int length) + { + if(bi_valid_ > (int)Buf_size - length) + { + bi_buf_ |= (std::uint16_t)value << bi_valid_; + put_short(bi_buf_); + bi_buf_ = (std::uint16_t)value >> (Buf_size - bi_valid_); + bi_valid_ += length - Buf_size; + } + else + { + bi_buf_ |= (std::uint16_t)(value) << bi_valid_; + bi_valid_ += length; + } + } + + // Send a code of the given tree + void + send_code(int value, ct_data const* tree) + { + send_bits(tree[value].fc, tree[value].dl); + } + + /* Mapping from a distance to a distance code. dist is the + distance - 1 and must not have side effects. _dist_code[256] + and _dist_code[257] are never used. + */ + std::uint8_t + d_code(unsigned dist) + { + if(dist < 256) + return lut_.dist_code[dist]; + return lut_.dist_code[256+(dist>>7)]; + } + + /* Update a hash value with the given input byte + IN assertion: all calls to to update_hash are made with + consecutive input characters, so that a running hash + key can be computed from the previous key instead of + complete recalculation each time. + */ + void + update_hash(uInt& h, std::uint8_t c) + { + h = ((h << hash_shift_) ^ c) & hash_mask_; + } + + /* Initialize the hash table (avoiding 64K overflow for 16 + bit systems). prev[] will be initialized on the fly. + */ + void + clear_hash() + { + head_[hash_size_-1] = 0; + std::memset((Byte *)head_, 0, + (unsigned)(hash_size_-1)*sizeof(*head_)); + } + + /* Compares two subtrees, using the tree depth as tie breaker + when the subtrees have equal frequency. This minimizes the + worst case length. + */ + bool + smaller(ct_data const* tree, int n, int m) + { + return tree[n].fc < tree[m].fc || + (tree[n].fc == tree[m].fc && + depth_[n] <= depth_[m]); + } + + /* Insert string str in the dictionary and set match_head to the + previous head of the hash chain (the most recent string with + same hash key). Return the previous length of the hash chain. + If this file is compiled with -DFASTEST, the compression level + is forced to 1, and no hash chains are maintained. + IN assertion: all calls to to INSERT_STRING are made with + consecutive input characters and the first minMatch + bytes of str are valid (except for the last minMatch-1 + bytes of the input file). + */ + void + insert_string(IPos& hash_head) + { + update_hash(ins_h_, window_[strstart_ + (minMatch-1)]); + hash_head = prev_[strstart_ & w_mask_] = head_[ins_h_]; + head_[ins_h_] = (std::uint16_t)strstart_; + } + + //-------------------------------------------------------------------------- + + /* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ + struct config + { + std::uint16_t good_length; /* reduce lazy search above this match length */ + std::uint16_t max_lazy; /* do not perform lazy search above this match length */ + std::uint16_t nice_length; /* quit search above this match length */ + std::uint16_t max_chain; + compress_func func; + + config( + std::uint16_t good_length_, + std::uint16_t max_lazy_, + std::uint16_t nice_length_, + std::uint16_t max_chain_, + compress_func func_) + : good_length(good_length_) + , max_lazy(max_lazy_) + , nice_length(nice_length_) + , max_chain(max_chain_) + , func(func_) + { + } + }; + + static + config + get_config(std::size_t level) + { + switch(level) + { + // good lazy nice chain + case 0: return { 0, 0, 0, 0, &self::deflate_stored}; // store only + case 1: return { 4, 4, 8, 4, &self::deflate_fast}; // max speed, no lazy matches + case 2: return { 4, 5, 16, 8, &self::deflate_fast}; + case 3: return { 4, 6, 32, 32, &self::deflate_fast}; + case 4: return { 4, 4, 16, 16, &self::deflate_slow}; // lazy matches + case 5: return { 8, 16, 32, 32, &self::deflate_slow}; + case 6: return { 8, 16, 128, 128, &self::deflate_slow}; + case 7: return { 8, 32, 128, 256, &self::deflate_slow}; + case 8: return { 32, 128, 258, 1024, &self::deflate_slow}; + default: + case 9: return { 32, 258, 258, 4096, &self::deflate_slow}; // max compression + } + } + + void + maybe_init() + { + if(! inited_) + init(); + } + + static + unsigned + bi_reverse(unsigned code, int len); + + template + static + void + gen_codes(ct_data *tree, int max_code, std::uint16_t *bl_count); + + template + static + lut_type const& + get_lut(); + + template void doReset (int level, int windowBits, int memLevel, Strategy strategy); + template void doReset (); + template void doClear (); + template std::size_t doUpperBound (std::size_t sourceLen) const; + template void doTune (int good_length, int max_lazy, int nice_length, int max_chain); + template void doParams (z_params& zs, int level, Strategy strategy, error_code& ec); + template void doWrite (z_params& zs, Flush flush, error_code& ec); + template void doDictionary (Byte const* dict, uInt dictLength, error_code& ec); + template void doPrime (int bits, int value, error_code& ec); + template void doPending (unsigned* value, int* bits); + + template void init (); + template void lm_init (); + template void init_block (); + template void pqdownheap (ct_data const* tree, int k); + template void pqremove (ct_data const* tree, int& top); + template void gen_bitlen (tree_desc *desc); + template void build_tree (tree_desc *desc); + template void scan_tree (ct_data *tree, int max_code); + template void send_tree (ct_data *tree, int max_code); + template int build_bl_tree (); + template void send_all_trees (int lcodes, int dcodes, int blcodes); + template void compress_block (ct_data const* ltree, ct_data const* dtree); + template int detect_data_type (); + template void bi_windup (); + template void bi_flush (); + template void copy_block (char *buf, unsigned len, int header); + + template void tr_init (); + template void tr_align (); + template void tr_flush_bits (); + template void tr_stored_block (char *bu, std::uint32_t stored_len, int last); + template void tr_tally_dist (std::uint16_t dist, std::uint8_t len, bool& flush); + template void tr_tally_lit (std::uint8_t c, bool& flush); + + template void tr_flush_block (z_params& zs, char *buf, std::uint32_t stored_len, int last); + template void fill_window (z_params& zs); + template void flush_pending (z_params& zs); + template void flush_block (z_params& zs, bool last); + template int read_buf (z_params& zs, Byte *buf, unsigned size); + template uInt longest_match (IPos cur_match); + + template block_state f_stored (z_params& zs, Flush flush); + template block_state f_fast (z_params& zs, Flush flush); + template block_state f_slow (z_params& zs, Flush flush); + template block_state f_rle (z_params& zs, Flush flush); + template block_state f_huff (z_params& zs, Flush flush); + + block_state + deflate_stored(z_params& zs, Flush flush) + { + return f_stored(zs, flush); + } + + block_state + deflate_fast(z_params& zs, Flush flush) + { + return f_fast(zs, flush); + } + + block_state + deflate_slow(z_params& zs, Flush flush) + { + return f_slow(zs, flush); + } + + block_state + deflate_rle(z_params& zs, Flush flush) + { + return f_rle(zs, flush); + } + + block_state + deflate_huff(z_params& zs, Flush flush) + { + return f_huff(zs, flush); + } +}; + +//-------------------------------------------------------------------------- + +// Reverse the first len bits of a code +inline +unsigned +deflate_stream:: +bi_reverse(unsigned code, int len) +{ + unsigned res = 0; + do + { + res |= code & 1; + code >>= 1; + res <<= 1; + } + while(--len > 0); + return res >> 1; +} + +/* Generate the codes for a given tree and bit counts (which need not be optimal). + IN assertion: the array bl_count contains the bit length statistics for + the given tree and the field len is set for all tree elements. + OUT assertion: the field code is set for all tree elements of non + zero code length. +*/ +template +void +deflate_stream:: +gen_codes(ct_data *tree, int max_code, std::uint16_t *bl_count) +{ + std::uint16_t next_code[maxBits+1]; /* next code value for each bit length */ + std::uint16_t code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + // The distribution counts are first used to + // generate the code values without bit reversal. + for(bits = 1; bits <= maxBits; bits++) + { + code = (code + bl_count[bits-1]) << 1; + next_code[bits] = code; + } + // Check that the bit counts in bl_count are consistent. + // The last code must be all ones. + BOOST_ASSERT(code + bl_count[maxBits]-1 == (1< +auto +deflate_stream::get_lut() -> + lut_type const& +{ + struct init + { + lut_type tables; + + init() + { + // number of codes at each bit length for an optimal tree + //std::uint16_t bl_count[maxBits+1]; + + // Initialize the mapping length (0..255) -> length code (0..28) + std::uint8_t length = 0; + for(std::uint8_t code = 0; code < lengthCodes-1; ++code) + { + tables.base_length[code] = length; + auto const run = 1U << tables.extra_lbits[code]; + for(unsigned n = 0; n < run; ++n) + tables.length_code[length++] = code; + } + BOOST_ASSERT(length == 0); + // Note that the length 255 (match length 258) can be represented + // in two different ways: code 284 + 5 bits or code 285, so we + // overwrite length_code[255] to use the best encoding: + tables.length_code[length-1] = lengthCodes-1; + + // Initialize the mapping dist (0..32K) -> dist code (0..29) + { + std::uint8_t code; + std::uint16_t dist = 0; + for(code = 0; code < 16; code++) + { + tables.base_dist[code] = dist; + auto const run = 1U << tables.extra_dbits[code]; + for(unsigned n = 0; n < run; ++n) + tables.dist_code[dist++] = code; + } + BOOST_ASSERT(dist == 256); + // from now on, all distances are divided by 128 + dist >>= 7; + for(; code < dCodes; ++code) + { + tables.base_dist[code] = dist << 7; + auto const run = 1U << (tables.extra_dbits[code]-7); + for(std::size_t n = 0; n < run; ++n) + tables.dist_code[256 + dist++] = code; + } + BOOST_ASSERT(dist == 256); + } + + // Construct the codes of the static literal tree + std::uint16_t bl_count[maxBits+1]; + std::memset(bl_count, 0, sizeof(bl_count)); + unsigned n = 0; + while (n <= 143) + tables.ltree[n++].dl = 8; + bl_count[8] += 144; + while (n <= 255) + tables.ltree[n++].dl = 9; + bl_count[9] += 112; + while (n <= 279) + tables.ltree[n++].dl = 7; + bl_count[7] += 24; + while (n <= 287) + tables.ltree[n++].dl = 8; + bl_count[8] += 8; + // Codes 286 and 287 do not exist, but we must include them in the tree + // construction to get a canonical Huffman tree (longest code all ones) + gen_codes(tables.ltree, lCodes+1, bl_count); + + for(n = 0; n < dCodes; ++n) + { + tables.dtree[n].dl = 5; + tables.dtree[n].fc = + static_cast(bi_reverse(n, 5)); + } + } + }; + static init const data; + return data.tables; +} + +template +void +deflate_stream:: +doReset( + int level, + int windowBits, + int memLevel, + Strategy strategy) +{ + if(level == Z_DEFAULT_COMPRESSION) + level = 6; + + // VFALCO What do we do about this? + // until 256-byte window bug fixed + if(windowBits == 8) + windowBits = 9; + + if(level < 0 || level > 9) + throw std::invalid_argument{"invalid level"}; + + if(windowBits < 8 || windowBits > 15) + throw std::invalid_argument{"invalid windowBits"}; + + if(memLevel < 1 || memLevel > MAX_MEM_LEVEL) + throw std::invalid_argument{"invalid memLevel"}; + + w_bits_ = windowBits; + + hash_bits_ = memLevel + 7; + + // 16K elements by default + lit_bufsize_ = 1 << (memLevel + 6); + + level_ = level; + strategy_ = strategy; + inited_ = false; +} + +template +void +deflate_stream:: +doReset() +{ + inited_ = false; +} + +template +void +deflate_stream:: +doClear() +{ + inited_ = false; + buf_.reset(); +} + +template +std::size_t +deflate_stream:: +doUpperBound(std::size_t sourceLen) const +{ + std::size_t complen; + std::size_t wraplen; + + /* conservative upper bound for compressed data */ + complen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + + /* compute wrapper length */ + wraplen = 0; + + /* if not default parameters, return conservative bound */ + if(w_bits_ != 15 || hash_bits_ != 8 + 7) + return complen + wraplen; + + /* default settings: return tight bound for that case */ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13 - 6 + wraplen; +} + +template +void +deflate_stream:: +doTune( + int good_length, + int max_lazy, + int nice_length, + int max_chain) +{ + good_match_ = good_length; + nice_match_ = nice_length; + max_lazy_match_ = max_lazy; + max_chain_length_ = max_chain; +} + +template +void +deflate_stream:: +doParams(z_params& zs, int level, Strategy strategy, error_code& ec) +{ + compress_func func; + + if(level == Z_DEFAULT_COMPRESSION) + level = 6; + if(level < 0 || level > 9) + { + ec = error::stream_error; + return; + } + func = get_config(level_).func; + + if((strategy != strategy_ || func != get_config(level).func) && + zs.total_in != 0) + { + // Flush the last buffer: + doWrite(zs, Flush::block, ec); + if(ec == error::need_buffers && pending_ == 0) + ec = {}; + } + if(level_ != level) + { + level_ = level; + max_lazy_match_ = get_config(level).max_lazy; + good_match_ = get_config(level).good_length; + nice_match_ = get_config(level).nice_length; + max_chain_length_ = get_config(level).max_chain; + } + strategy_ = strategy; +} + +template +void +deflate_stream:: +doWrite(z_params& zs, Flush flush, error_code& ec) +{ + maybe_init(); + + if(zs.next_out == 0 || (zs.next_in == 0 && zs.avail_in != 0) || + (status_ == FINISH_STATE && flush != Flush::finish)) + { + ec = error::stream_error; + return; + } + if(zs.avail_out == 0) + { + ec = error::need_buffers; + return; + } + + // value of flush param for previous deflate call + boost::optional old_flush = last_flush_; + last_flush_ = flush; + + // Flush as much pending output as possible + if(pending_ != 0) + { + flush_pending(zs); + if(zs.avail_out == 0) + { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + last_flush_ = boost::none; + return; + } + } + else if(zs.avail_in == 0 && flush <= old_flush && + flush != Flush::finish) + { + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Flush::finish, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + ec = error::need_buffers; + return; + } + + // User must not provide more input after the first FINISH: + if(status_ == FINISH_STATE && zs.avail_in != 0) + { + ec = error::need_buffers; + return; + } + + /* Start a new block or continue the current one. + */ + if(zs.avail_in != 0 || lookahead_ != 0 || + (flush != Flush::none && status_ != FINISH_STATE)) + { + block_state bstate; + + switch(strategy_) + { + case Strategy::huffman: + bstate = deflate_huff(zs, flush); + break; + case Strategy::rle: + bstate = deflate_rle(zs, flush); + break; + default: + { + bstate = (this->*(get_config(level_).func))(zs, flush); + break; + } + } + + if(bstate == finish_started || bstate == finish_done) + { + status_ = FINISH_STATE; + } + if(bstate == need_more || bstate == finish_started) + { + if(zs.avail_out == 0) + { + last_flush_ = boost::none; /* avoid BUF_ERROR next call, see above */ + } + return; + /* If flush != Flush::none && avail_out == 0, the next call + of deflate should use the same flush parameter to make sure + that the flush is complete. So we don't have to output an + empty block here, this will be done at next call. This also + ensures that for a very small output buffer, we emit at most + one empty block. + */ + } + if(bstate == block_done) + { + if(flush == Flush::partial) + { + tr_align(); + } + else if(flush != Flush::block) + { + /* FULL_FLUSH or SYNC_FLUSH */ + tr_stored_block((char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if(flush == Flush::full) + { + clear_hash(); // forget history + if(lookahead_ == 0) + { + strstart_ = 0; + block_start_ = 0L; + insert_ = 0; + } + } + } + flush_pending(zs); + if(zs.avail_out == 0) + { + last_flush_ = boost::none; /* avoid BUF_ERROR at next call, see above */ + return; + } + } + } + + if(flush == Flush::finish) + { + ec = error::end_of_stream; + return; + } +} + +// VFALCO Warning: untested +template +void +deflate_stream:: +doDictionary(Byte const* dict, uInt dictLength, error_code& ec) +{ + if(lookahead_) + { + ec = error::stream_error; + return; + } + + maybe_init(); + + /* if dict would fill window, just replace the history */ + if(dictLength >= w_size_) + { + clear_hash(); + strstart_ = 0; + block_start_ = 0L; + insert_ = 0; + dict += dictLength - w_size_; /* use the tail */ + dictLength = w_size_; + } + + /* insert dict into window and hash */ + z_params zs; + zs.avail_in = dictLength; + zs.next_in = (const Byte *)dict; + zs.avail_out = 0; + zs.next_out = 0; + fill_window(zs); + while(lookahead_ >= minMatch) + { + uInt str = strstart_; + uInt n = lookahead_ - (minMatch-1); + do + { + update_hash(ins_h_, window_[str + minMatch-1]); + prev_[str & w_mask_] = head_[ins_h_]; + head_[ins_h_] = (std::uint16_t)str; + str++; + } + while(--n); + strstart_ = str; + lookahead_ = minMatch-1; + fill_window(zs); + } + strstart_ += lookahead_; + block_start_ = (long)strstart_; + insert_ = lookahead_; + lookahead_ = 0; + match_length_ = prev_length_ = minMatch-1; + match_available_ = 0; +} + +template +void +deflate_stream:: +doPrime(int bits, int value, error_code& ec) +{ + maybe_init(); + + if((Byte *)(d_buf_) < pending_out_ + ((Buf_size + 7) >> 3)) + { + ec = error::need_buffers; + return; + } + + do + { + int put = Buf_size - bi_valid_; + if(put > bits) + put = bits; + bi_buf_ |= (std::uint16_t)((value & ((1 << put) - 1)) << bi_valid_); + bi_valid_ += put; + tr_flush_bits(); + value >>= put; + bits -= put; + } + while(bits); +} + +template +void +deflate_stream:: +doPending(unsigned* value, int* bits) +{ + if(value != 0) + *value = pending_; + if(bits != 0) + *bits = bi_valid_; +} + +//-------------------------------------------------------------------------- + +// Do lazy initialization +template +void +deflate_stream:: +init() +{ + // Caller must set these: + // w_bits_ + // hash_bits_ + // lit_bufsize_ + // level_ + // strategy_ + + w_size_ = 1 << w_bits_; + w_mask_ = w_size_ - 1; + + hash_size_ = 1 << hash_bits_; + hash_mask_ = hash_size_ - 1; + hash_shift_ = ((hash_bits_+minMatch-1)/minMatch); + + auto const nwindow = w_size_ * 2*sizeof(Byte); + auto const nprev = w_size_ * sizeof(std::uint16_t); + auto const nhead = hash_size_ * sizeof(std::uint16_t); + auto const noverlay = lit_bufsize_ * (sizeof(std::uint16_t)+2); + auto const needed = nwindow + nprev + nhead + noverlay; + + if(! buf_ || buf_size_ != needed) + { + buf_.reset(new std::uint8_t[needed]); + buf_size_ = needed; + } + + window_ = reinterpret_cast(buf_.get()); + prev_ = reinterpret_cast(buf_.get() + nwindow); + head_ = reinterpret_cast(buf_.get() + nwindow + nprev); + + /* We overlay pending_buf_ and d_buf_ + l_buf_. This works + since the average output size for(length, distance) + codes is <= 24 bits. + */ + auto overlay = reinterpret_cast( + buf_.get() + nwindow + nprev + nhead); + + // nothing written to window_ yet + high_water_ = 0; + + pending_buf_ = + reinterpret_cast(overlay); + pending_buf_size_ = + static_cast(lit_bufsize_) * + (sizeof(std::uint16_t) + 2L); + + d_buf_ = overlay + lit_bufsize_ / sizeof(std::uint16_t); + l_buf_ = pending_buf_ + (1 + sizeof(std::uint16_t)) * lit_bufsize_; + + pending_ = 0; + pending_out_ = pending_buf_; + + status_ = BUSY_STATE; + last_flush_ = Flush::none; + + tr_init(); + lm_init(); + + inited_ = true; +} + +/* Initialize the "longest match" routines for a new zlib stream +*/ +template +void +deflate_stream:: +lm_init() +{ + window_size_ = (std::uint32_t)2L*w_size_; + + clear_hash(); + + /* Set the default configuration parameters: + */ + // VFALCO TODO just copy the config struct + max_lazy_match_ = get_config(level_).max_lazy; + good_match_ = get_config(level_).good_length; + nice_match_ = get_config(level_).nice_length; + max_chain_length_ = get_config(level_).max_chain; + + strstart_ = 0; + block_start_ = 0L; + lookahead_ = 0; + insert_ = 0; + match_length_ = prev_length_ = minMatch-1; + match_available_ = 0; + ins_h_ = 0; +} + +// Initialize a new block. +// +template +void +deflate_stream:: +init_block() +{ + for(int n = 0; n < lCodes; n++) + dyn_ltree_[n].fc = 0; + for(int n = 0; n < dCodes; n++) + dyn_dtree_[n].fc = 0; + for(int n = 0; n < blCodes; n++) + bl_tree_[n].fc = 0; + dyn_ltree_[END_BLOCK].fc = 1; + opt_len_ = 0L; + static_len_ = 0L; + last_lit_ = 0; + matches_ = 0; +} + +/* Restore the heap property by moving down the tree starting at node k, + exchanging a node with the smallest of its two sons if necessary, + stopping when the heap property is re-established (each father smaller + than its two sons). +*/ +template +void +deflate_stream:: +pqdownheap( + ct_data const* tree, // the tree to restore + int k) // node to move down +{ + int v = heap_[k]; + int j = k << 1; // left son of k + while(j <= heap_len_) + { + // Set j to the smallest of the two sons: + if(j < heap_len_ && + smaller(tree, heap_[j+1], heap_[j])) + j++; + // Exit if v is smaller than both sons + if(smaller(tree, v, heap_[j])) + break; + + // Exchange v with the smallest son + heap_[k] = heap_[j]; + k = j; + + // And continue down the tree, + // setting j to the left son of k + j <<= 1; + } + heap_[k] = v; +} + +/* Remove the smallest element from the heap and recreate the heap + with one less element. Updates heap and heap_len. +*/ +template +inline +void +deflate_stream:: +pqremove(ct_data const* tree, int& top) +{ + top = heap_[kSmallest]; + heap_[kSmallest] = heap_[heap_len_--]; + pqdownheap(tree, kSmallest); +} + +/* Compute the optimal bit lengths for a tree and update the total bit length + for the current block. + IN assertion: the fields freq and dad are set, heap[heap_max] and + above are the tree nodes sorted by increasing frequency. + OUT assertions: the field len is set to the optimal bit length, the + array bl_count contains the frequencies for each bit length. + The length opt_len is updated; static_len is also updated if stree is + not null. +*/ +template +void +deflate_stream:: +gen_bitlen(tree_desc *desc) +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + ct_data const* stree = desc->stat_desc->static_tree; + std::uint8_t const *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; // heap index + int n, m; // iterate over the tree elements + int bits; // bit length + int xbits; // extra bits + std::uint16_t f; // frequency + int overflow = 0; // number of elements with bit length too large + + std::fill(&bl_count_[0], &bl_count_[maxBits+1], 0); + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[heap_[heap_max_]].dl = 0; // root of the heap + + for(h = heap_max_+1; h < HEAP_SIZE; h++) { + n = heap_[h]; + bits = tree[tree[n].dl].dl + 1; + if(bits > max_length) bits = max_length, overflow++; + // We overwrite tree[n].dl which is no longer needed + tree[n].dl = (std::uint16_t)bits; + + if(n > max_code) + continue; // not a leaf node + + bl_count_[bits]++; + xbits = 0; + if(n >= base) + xbits = extra[n-base]; + f = tree[n].fc; + opt_len_ += (std::uint32_t)f * (bits + xbits); + if(stree) + static_len_ += (std::uint32_t)f * (stree[n].dl + xbits); + } + if(overflow == 0) + return; + + // Find the first bit length which could increase: + do + { + bits = max_length-1; + while(bl_count_[bits] == 0) + bits--; + bl_count_[bits]--; // move one leaf down the tree + bl_count_[bits+1] += 2; // move one overflow item as its brother + bl_count_[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } + while(overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for(bits = max_length; bits != 0; bits--) + { + n = bl_count_[bits]; + while(n != 0) + { + m = heap_[--h]; + if(m > max_code) + continue; + if((unsigned) tree[m].dl != (unsigned) bits) + { + opt_len_ += ((long)bits - (long)tree[m].dl) *(long)tree[m].fc; + tree[m].dl = (std::uint16_t)bits; + } + n--; + } + } +} + +/* Construct one Huffman tree and assigns the code bit strings and lengths. + Update the total bit length for the current block. + IN assertion: the field freq is set for all tree elements. + OUT assertions: the fields len and code are set to the optimal bit length + and corresponding code. The length opt_len is updated; static_len is + also updated if stree is not null. The field max_code is set. +*/ +template +void +deflate_stream:: +build_tree(tree_desc *desc) +{ + ct_data *tree = desc->dyn_tree; + ct_data const* stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; // iterate over heap elements + int max_code = -1; // largest code with non zero frequency + int node; // new node being created + + /* Construct the initial heap, with least frequent element in + * heap[kSmallest]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + heap_len_ = 0; + heap_max_ = HEAP_SIZE; + + for(n = 0; n < elems; n++) + { + if(tree[n].fc != 0) + { + heap_[++(heap_len_)] = max_code = n; + depth_[n] = 0; + } + else + { + tree[n].dl = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while(heap_len_ < 2) + { + node = heap_[++(heap_len_)] = (max_code < 2 ? ++max_code : 0); + tree[node].fc = 1; + depth_[node] = 0; + opt_len_--; + if(stree) + static_len_ -= stree[node].dl; + // node is 0 or 1 so it does not have extra bits + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for(n = heap_len_/2; n >= 1; n--) + pqdownheap(tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do + { + pqremove(tree, n); /* n = node of least frequency */ + m = heap_[kSmallest]; /* m = node of next least frequency */ + + heap_[--(heap_max_)] = n; /* keep the nodes sorted by frequency */ + heap_[--(heap_max_)] = m; + + /* Create a new node father of n and m */ + tree[node].fc = tree[n].fc + tree[m].fc; + depth_[node] = (std::uint8_t)((depth_[n] >= depth_[m] ? + depth_[n] : depth_[m]) + 1); + tree[n].dl = tree[m].dl = (std::uint16_t)node; + /* and insert the new node in the heap */ + heap_[kSmallest] = node++; + pqdownheap(tree, kSmallest); + + } + while(heap_len_ >= 2); + + heap_[--(heap_max_)] = heap_[kSmallest]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen((tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes(tree, max_code, bl_count_); +} + +/* Scan a literal or distance tree to determine the frequencies + of the codes in the bit length tree. +*/ +template +void +deflate_stream:: +scan_tree( + ct_data *tree, // the tree to be scanned + int max_code) // and its largest code of non zero frequency +{ + int n; // iterates over all tree elements + int prevlen = -1; // last emitted length + int curlen; // length of current code + int nextlen = tree[0].dl; // length of next code + int count = 0; // repeat count of the current code + int max_count = 7; // max repeat count + int min_count = 4; // min repeat count + + if(nextlen == 0) + { + max_count = 138; + min_count = 3; + } + tree[max_code+1].dl = (std::uint16_t)0xffff; // guard + + for(n = 0; n <= max_code; n++) + { + curlen = nextlen; nextlen = tree[n+1].dl; + if(++count < max_count && curlen == nextlen) + { + continue; + } + else if(count < min_count) + { + bl_tree_[curlen].fc += count; + } + else if(curlen != 0) + { + if(curlen != prevlen) bl_tree_[curlen].fc++; + bl_tree_[REP_3_6].fc++; + } + else if(count <= 10) + { + bl_tree_[REPZ_3_10].fc++; + } + else + { + bl_tree_[REPZ_11_138].fc++; + } + count = 0; + prevlen = curlen; + if(nextlen == 0) + { + max_count = 138; + min_count = 3; + } + else if(curlen == nextlen) + { + max_count = 6; + min_count = 3; + } + else + { + max_count = 7; + min_count = 4; + } + } +} + +/* Send a literal or distance tree in compressed form, + using the codes in bl_tree. +*/ +template +void +deflate_stream:: +send_tree( + ct_data *tree, // the tree to be scanned + int max_code) // and its largest code of non zero frequency +{ + int n; // iterates over all tree elements + int prevlen = -1; // last emitted length + int curlen; // length of current code + int nextlen = tree[0].dl; // length of next code + int count = 0; // repeat count of the current code + int max_count = 7; // max repeat count + int min_count = 4; // min repeat count + + // tree[max_code+1].dl = -1; // guard already set + if(nextlen == 0) + { + max_count = 138; + min_count = 3; + } + + for(n = 0; n <= max_code; n++) + { + curlen = nextlen; + nextlen = tree[n+1].dl; + if(++count < max_count && curlen == nextlen) + { + continue; + } + else if(count < min_count) + { + do + { + send_code(curlen, bl_tree_); + } + while (--count != 0); + } + else if(curlen != 0) + { + if(curlen != prevlen) + { + send_code(curlen, bl_tree_); + count--; + } + BOOST_ASSERT(count >= 3 && count <= 6); + send_code(REP_3_6, bl_tree_); + send_bits(count-3, 2); + } + else if(count <= 10) + { + send_code(REPZ_3_10, bl_tree_); + send_bits(count-3, 3); + } + else + { + send_code(REPZ_11_138, bl_tree_); + send_bits(count-11, 7); + } + count = 0; + prevlen = curlen; + if(nextlen == 0) + { + max_count = 138; + min_count = 3; + } + else if(curlen == nextlen) + { + max_count = 6; + min_count = 3; + } + else + { + max_count = 7; + min_count = 4; + } + } +} + +/* Construct the Huffman tree for the bit lengths and return + the index in bl_order of the last bit length code to send. +*/ +template +int +deflate_stream:: +build_bl_tree() +{ + int max_blindex; // index of last bit length code of non zero freq + + // Determine the bit length frequencies for literal and distance trees + scan_tree((ct_data *)dyn_ltree_, l_desc_.max_code); + scan_tree((ct_data *)dyn_dtree_, d_desc_.max_code); + + // Build the bit length tree: + build_tree((tree_desc *)(&(bl_desc_))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for(max_blindex = blCodes-1; max_blindex >= 3; max_blindex--) + { + if(bl_tree_[lut_.bl_order[max_blindex]].dl != 0) + break; + } + // Update opt_len to include the bit length tree and counts + opt_len_ += 3*(max_blindex+1) + 5+5+4; + return max_blindex; +} + +/* Send the header for a block using dynamic Huffman trees: the counts, + the lengths of the bit length codes, the literal tree and the distance + tree. + IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. +*/ +template +void +deflate_stream:: +send_all_trees( + int lcodes, + int dcodes, + int blcodes) // number of codes for each tree +{ + int rank; // index in bl_order + + BOOST_ASSERT(lcodes >= 257 && dcodes >= 1 && blcodes >= 4); + BOOST_ASSERT(lcodes <= lCodes && dcodes <= dCodes && blcodes <= blCodes); + send_bits(lcodes-257, 5); // not +255 as stated in appnote.txt + send_bits(dcodes-1, 5); + send_bits(blcodes-4, 4); // not -3 as stated in appnote.txt + for(rank = 0; rank < blcodes; rank++) + send_bits(bl_tree_[lut_.bl_order[rank]].dl, 3); + send_tree((ct_data *)dyn_ltree_, lcodes-1); // literal tree + send_tree((ct_data *)dyn_dtree_, dcodes-1); // distance tree +} + +/* Send the block data compressed using the given Huffman trees +*/ +template +void +deflate_stream:: +compress_block( + ct_data const* ltree, // literal tree + ct_data const* dtree) // distance tree +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if(last_lit_ != 0) + { + do + { + dist = d_buf_[lx]; + lc = l_buf_[lx++]; + if(dist == 0) + { + send_code(lc, ltree); /* send a literal byte */ + } + else + { + /* Here, lc is the match length - minMatch */ + code = lut_.length_code[lc]; + send_code(code+literals+1, ltree); /* send the length code */ + extra = lut_.extra_lbits[code]; + if(extra != 0) + { + lc -= lut_.base_length[code]; + send_bits(lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + BOOST_ASSERT(code < dCodes); + + send_code(code, dtree); /* send the distance code */ + extra = lut_.extra_dbits[code]; + if(extra != 0) + { + dist -= lut_.base_dist[code]; + send_bits(dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + BOOST_ASSERT((uInt)(pending_) < lit_bufsize_ + 2*lx); + } + while(lx < last_lit_); + } + + send_code(END_BLOCK, ltree); +} + +/* Check if the data type is TEXT or BINARY, using the following algorithm: + - TEXT if the two conditions below are satisfied: + a) There are no non-portable control characters belonging to the + "black list" (0..6, 14..25, 28..31). + b) There is at least one printable character belonging to the + "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + - BINARY otherwise. + - The following partially-portable control characters form a + "gray list" that is ignored in this detection algorithm: + (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + IN assertion: the fields fc of dyn_ltree are set. +*/ +template +int +deflate_stream:: +detect_data_type() +{ + /* black_mask is the bit mask of black-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + unsigned long black_mask = 0xf3ffc07fUL; + int n; + + // Check for non-textual ("black-listed") bytes. + for(n = 0; n <= 31; n++, black_mask >>= 1) + if((black_mask & 1) && (dyn_ltree_[n].fc != 0)) + return Z_BINARY; + + // Check for textual ("white-listed") bytes. */ + if(dyn_ltree_[9].fc != 0 || dyn_ltree_[10].fc != 0 + || dyn_ltree_[13].fc != 0) + return Z_TEXT; + for(n = 32; n < literals; n++) + if(dyn_ltree_[n].fc != 0) + return Z_TEXT; + + /* There are no "black-listed" or "white-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + +/* Flush the bit buffer and align the output on a byte boundary +*/ +template +void +deflate_stream:: +bi_windup() +{ + if(bi_valid_ > 8) + put_short(bi_buf_); + else if(bi_valid_ > 0) + put_byte((Byte)bi_buf_); + bi_buf_ = 0; + bi_valid_ = 0; +} + +/* Flush the bit buffer, keeping at most 7 bits in it. +*/ +template +void +deflate_stream:: +bi_flush() +{ + if(bi_valid_ == 16) + { + put_short(bi_buf_); + bi_buf_ = 0; + bi_valid_ = 0; + } + else if(bi_valid_ >= 8) + { + put_byte((Byte)bi_buf_); + bi_buf_ >>= 8; + bi_valid_ -= 8; + } +} + +/* Copy a stored block, storing first the length and its + one's complement if requested. +*/ +template +void +deflate_stream:: +copy_block( + char *buf, // the input data + unsigned len, // its length + int header) // true if block header must be written +{ + bi_windup(); // align on byte boundary + + if(header) + { + put_short((std::uint16_t)len); + put_short((std::uint16_t)~len); + } + // VFALCO Use memcpy? + while (len--) + put_byte(*buf++); +} + +//------------------------------------------------------------------------------ + +/* Initialize the tree data structures for a new zlib stream. +*/ +template +void +deflate_stream:: +tr_init() +{ + l_desc_.dyn_tree = dyn_ltree_; + l_desc_.stat_desc = &lut_.l_desc; + + d_desc_.dyn_tree = dyn_dtree_; + d_desc_.stat_desc = &lut_.d_desc; + + bl_desc_.dyn_tree = bl_tree_; + bl_desc_.stat_desc = &lut_.bl_desc; + + bi_buf_ = 0; + bi_valid_ = 0; + + // Initialize the first block of the first file: + init_block(); +} + +/* Send one empty static block to give enough lookahead for inflate. + This takes 10 bits, of which 7 may remain in the bit buffer. +*/ +template +void +deflate_stream:: +tr_align() +{ + send_bits(STATIC_TREES<<1, 3); + send_code(END_BLOCK, lut_.ltree); + bi_flush(); +} + +/* Flush the bits in the bit buffer to pending output (leaves at most 7 bits) +*/ +template +void +deflate_stream:: +tr_flush_bits() +{ + bi_flush(); +} + +/* Send a stored block +*/ +template +void +deflate_stream:: +tr_stored_block( + char *buf, // input block + std::uint32_t stored_len, // length of input block + int last) // one if this is the last block for a file +{ + send_bits((STORED_BLOCK<<1)+last, 3); // send block type + copy_block(buf, (unsigned)stored_len, 1); // with header +} + +template +inline +void +deflate_stream:: +tr_tally_dist(std::uint16_t dist, std::uint8_t len, bool& flush) +{ + d_buf_[last_lit_] = dist; + l_buf_[last_lit_++] = len; + dist--; + dyn_ltree_[lut_.length_code[len]+literals+1].fc++; + dyn_dtree_[d_code(dist)].fc++; + flush = (last_lit_ == lit_bufsize_-1); +} + +template +inline +void +deflate_stream:: +tr_tally_lit(std::uint8_t c, bool& flush) +{ + d_buf_[last_lit_] = 0; + l_buf_[last_lit_++] = c; + dyn_ltree_[c].fc++; + flush = (last_lit_ == lit_bufsize_-1); +} + +//------------------------------------------------------------------------------ + +/* Determine the best encoding for the current block: dynamic trees, + static trees or store, and output the encoded block to the zip file. +*/ +template +void +deflate_stream:: +tr_flush_block( + z_params& zs, + char *buf, // input block, or NULL if too old + std::uint32_t stored_len, // length of input block + int last) // one if this is the last block for a file +{ + std::uint32_t opt_lenb; + std::uint32_t static_lenb; // opt_len and static_len in bytes + int max_blindex = 0; // index of last bit length code of non zero freq + + // Build the Huffman trees unless a stored block is forced + if(level_ > 0) + { + // Check if the file is binary or text + if(zs.data_type == Z_UNKNOWN) + zs.data_type = detect_data_type(); + + // Construct the literal and distance trees + build_tree((tree_desc *)(&(l_desc_))); + + build_tree((tree_desc *)(&(d_desc_))); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (opt_len_+3+7)>>3; + static_lenb = (static_len_+3+7)>>3; + + if(static_lenb <= opt_lenb) + opt_lenb = static_lenb; + } + else + { + // VFALCO This assertion fails even in the original ZLib, + // happens with strategy == Z_HUFFMAN_ONLY, see: + // https://github.com/madler/zlib/issues/172 + + #if 0 + BOOST_ASSERT(buf); + #endif + opt_lenb = static_lenb = stored_len + 5; // force a stored block + } + +#ifdef FORCE_STORED + if(buf != (char*)0) { /* force stored block */ +#else + if(stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + tr_stored_block(buf, stored_len, last); + +#ifdef FORCE_STATIC + } + else if(static_lenb >= 0) + { + // force static trees +#else + } + else if(strategy_ == Strategy::fixed || static_lenb == opt_lenb) + { +#endif + send_bits((STATIC_TREES<<1)+last, 3); + compress_block(lut_.ltree, lut_.dtree); + } + else + { + send_bits((DYN_TREES<<1)+last, 3); + send_all_trees(l_desc_.max_code+1, d_desc_.max_code+1, + max_blindex+1); + compress_block((const ct_data *)dyn_ltree_, + (const ct_data *)dyn_dtree_); + } + /* The above check is made mod 2^32, for files larger than 512 MB + * and std::size_t implemented on 32 bits. + */ + init_block(); + + if(last) + bi_windup(); +} + +template +void +deflate_stream:: +fill_window(z_params& zs) +{ + unsigned n, m; + unsigned more; // Amount of free space at the end of the window. + std::uint16_t *p; + uInt wsize = w_size_; + + do + { + more = (unsigned)(window_size_ - + (std::uint32_t)lookahead_ -(std::uint32_t)strstart_); + + // VFALCO We don't support systems below 32-bit + #if 0 + // Deal with !@#$% 64K limit: + if(sizeof(int) <= 2) + { + if(more == 0 && strstart_ == 0 && lookahead_ == 0) + { + more = wsize; + } + else if(more == (unsigned)(-1)) + { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + #endif + + /* If the window is almost full and there is insufficient lookahead, + move the upper half to the lower one to make room in the upper half. + */ + if(strstart_ >= wsize+max_dist()) + { + std::memcpy(window_, window_+wsize, (unsigned)wsize); + match_start_ -= wsize; + strstart_ -= wsize; // we now have strstart >= max_dist + block_start_ -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = hash_size_; + p = &head_[n]; + do + { + m = *--p; + *p = (std::uint16_t)(m >= wsize ? m-wsize : 0); + } + while(--n); + + n = wsize; + p = &prev_[n]; + do + { + m = *--p; + *p = (std::uint16_t)(m >= wsize ? m-wsize : 0); + /* If n is not on any hash chain, prev[n] is garbage but + its value will never be used. + */ + } + while(--n); + more += wsize; + } + if(zs.avail_in == 0) + break; + + /* If there was no sliding: + strstart <= WSIZE+max_dist-1 && lookahead <= kMinLookahead - 1 && + more == window_size - lookahead - strstart + => more >= window_size - (kMinLookahead-1 + WSIZE + max_dist-1) + => more >= window_size - 2*WSIZE + 2 + In the BIG_MEM or MMAP case (not yet supported), + window_size == input_size + kMinLookahead && + strstart + lookahead_ <= input_size => more >= kMinLookahead. + Otherwise, window_size == 2*WSIZE so more >= 2. + If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + n = read_buf(zs, window_ + strstart_ + lookahead_, more); + lookahead_ += n; + + // Initialize the hash value now that we have some input: + if(lookahead_ + insert_ >= minMatch) + { + uInt str = strstart_ - insert_; + ins_h_ = window_[str]; + update_hash(ins_h_, window_[str + 1]); + while(insert_) + { + update_hash(ins_h_, window_[str + minMatch-1]); + prev_[str & w_mask_] = head_[ins_h_]; + head_[ins_h_] = (std::uint16_t)str; + str++; + insert_--; + if(lookahead_ + insert_ < minMatch) + break; + } + } + /* If the whole input has less than minMatch bytes, ins_h is garbage, + but this is not important since only literal bytes will be emitted. + */ + } + while(lookahead_ < kMinLookahead && zs.avail_in != 0); + + /* If the kWinInit bytes after the end of the current data have never been + written, then zero those bytes in order to avoid memory check reports of + the use of uninitialized (or uninitialised as Julian writes) bytes by + the longest match routines. Update the high water mark for the next + time through here. kWinInit is set to maxMatch since the longest match + routines allow scanning to strstart + maxMatch, ignoring lookahead. + */ + if(high_water_ < window_size_) + { + std::uint32_t curr = strstart_ + (std::uint32_t)(lookahead_); + std::uint32_t init; + + if(high_water_ < curr) + { + /* Previous high water mark below current data -- zero kWinInit + bytes or up to end of window, whichever is less. + */ + init = window_size_ - curr; + if(init > kWinInit) + init = kWinInit; + std::memset(window_ + curr, 0, (unsigned)init); + high_water_ = curr + init; + } + else if(high_water_ < (std::uint32_t)curr + kWinInit) + { + /* High water mark at or above current data, but below current data + plus kWinInit -- zero out to current data plus kWinInit, or up + to end of window, whichever is less. + */ + init = (std::uint32_t)curr + kWinInit - high_water_; + if(init > window_size_ - high_water_) + init = window_size_ - high_water_; + std::memset(window_ + high_water_, 0, (unsigned)init); + high_water_ += init; + } + } +} + +/* Flush as much pending output as possible. All write() output goes + through this function so some applications may wish to modify it + to avoid allocating a large strm->next_out buffer and copying into it. + (See also read_buf()). +*/ +template +void +deflate_stream:: +flush_pending(z_params& zs) +{ + tr_flush_bits(); + auto len = clamp(pending_, zs.avail_out); + if(len == 0) + return; + + std::memcpy(zs.next_out, pending_out_, len); + zs.next_out = + static_cast(zs.next_out) + len; + pending_out_ += len; + zs.total_out += len; + zs.avail_out -= len; + pending_ -= len; + if(pending_ == 0) + pending_out_ = pending_buf_; +} + +/* Flush the current block, with given end-of-file flag. + IN assertion: strstart is set to the end of the current match. +*/ +template +inline +void +deflate_stream:: +flush_block(z_params& zs, bool last) +{ + tr_flush_block(zs, + (block_start_ >= 0L ? + (char *)&window_[(unsigned)block_start_] : + (char *)0), + (std::uint32_t)((long)strstart_ - block_start_), + last); + block_start_ = strstart_; + flush_pending(zs); +} + +/* Read a new buffer from the current input stream, update the adler32 + and total number of bytes read. All write() input goes through + this function so some applications may wish to modify it to avoid + allocating a large strm->next_in buffer and copying from it. + (See also flush_pending()). +*/ +template +int +deflate_stream:: +read_buf(z_params& zs, Byte *buf, unsigned size) +{ + auto len = clamp(zs.avail_in, size); + if(len == 0) + return 0; + + zs.avail_in -= len; + + std::memcpy(buf, zs.next_in, len); + zs.next_in = static_cast< + std::uint8_t const*>(zs.next_in) + len; + zs.total_in += len; + return (int)len; +} + +/* Set match_start to the longest match starting at the given string and + return its length. Matches shorter or equal to prev_length are discarded, + in which case the result is equal to prev_length and match_start is + garbage. + IN assertions: cur_match is the head of the hash chain for the current + string (strstart) and its distance is <= max_dist, and prev_length >= 1 + OUT assertion: the match length is not greater than s->lookahead_. + + For 80x86 and 680x0, an optimized version will be provided in match.asm or + match.S. The code will be functionally equivalent. +*/ +template +uInt +deflate_stream:: +longest_match(IPos cur_match) +{ + unsigned chain_length = max_chain_length_;/* max hash chain length */ + Byte *scan = window_ + strstart_; /* current string */ + Byte *match; /* matched string */ + int len; /* length of current match */ + int best_len = prev_length_; /* best match length so far */ + int nice_match = nice_match_; /* stop if match long enough */ + IPos limit = strstart_ > (IPos)max_dist() ? + strstart_ - (IPos)max_dist() : 0; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + std::uint16_t *prev = prev_; + uInt wmask = w_mask_; + + Byte *strend = window_ + strstart_ + maxMatch; + Byte scan_end1 = scan[best_len-1]; + Byte scan_end = scan[best_len]; + + /* The code is optimized for HASH_BITS >= 8 and maxMatch-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + BOOST_ASSERT(hash_bits_ >= 8 && maxMatch == 258); + + /* Do not waste too much time if we already have a good match: */ + if(prev_length_ >= good_match_) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if((uInt)nice_match > lookahead_) + nice_match = lookahead_; + + BOOST_ASSERT((std::uint32_t)strstart_ <= window_size_-kMinLookahead); + + do { + BOOST_ASSERT(cur_match < strstart_); + match = window_ + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ + if( match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) + continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + BOOST_ASSERT(*scan == *match); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do + { + } + while( *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + BOOST_ASSERT(scan <= window_+(unsigned)(window_size_-1)); + + len = maxMatch - (int)(strend - scan); + scan = strend - maxMatch; + + if(len > best_len) { + match_start_ = cur_match; + best_len = len; + if(len >= nice_match) break; + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; + } + } + while((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if((uInt)best_len <= lookahead_) + return (uInt)best_len; + return lookahead_; +} + +//------------------------------------------------------------------------------ + +/* Copy without compression as much as possible from the input stream, return + the current block state. + This function does not insert new strings in the dictionary since + uncompressible data is probably not useful. This function is used + only for the level=0 compression option. + NOTE: this function should be optimized to avoid extra copying from + window to pending_buf. +*/ +template +inline +auto +deflate_stream:: +f_stored(z_params& zs, Flush flush) -> + block_state +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + std::uint32_t max_block_size = 0xffff; + std::uint32_t max_start; + + if(max_block_size > pending_buf_size_ - 5) { + max_block_size = pending_buf_size_ - 5; + } + + /* Copy as much as possible from input to output: */ + for(;;) { + /* Fill the window as much as possible: */ + if(lookahead_ <= 1) { + + BOOST_ASSERT(strstart_ < w_size_+max_dist() || + block_start_ >= (long)w_size_); + + fill_window(zs); + if(lookahead_ == 0 && flush == Flush::none) + return need_more; + + if(lookahead_ == 0) break; /* flush the current block */ + } + BOOST_ASSERT(block_start_ >= 0L); + + strstart_ += lookahead_; + lookahead_ = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = block_start_ + max_block_size; + if(strstart_ == 0 || (std::uint32_t)strstart_ >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + lookahead_ = (uInt)(strstart_ - max_start); + strstart_ = (uInt)max_start; + flush_block(zs, false); + if(zs.avail_out == 0) + return need_more; + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if(strstart_ - (uInt)block_start_ >= max_dist()) { + flush_block(zs, false); + if(zs.avail_out == 0) + return need_more; + } + } + insert_ = 0; + if(flush == Flush::finish) + { + flush_block(zs, true); + if(zs.avail_out == 0) + return finish_started; + return finish_done; + } + if((long)strstart_ > block_start_) + { + flush_block(zs, false); + if(zs.avail_out == 0) + return need_more; + } + return block_done; +} + +/* Compress as much as possible from the input stream, return the current + block state. + This function does not perform lazy evaluation of matches and inserts + new strings in the dictionary only for unmatched strings or for short + matches. It is used only for the fast compression options. +*/ +template +inline +auto +deflate_stream:: +f_fast(z_params& zs, Flush flush) -> + block_state +{ + IPos hash_head; /* head of the hash chain */ + bool bflush; /* set if current block must be flushed */ + + for(;;) + { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need maxMatch bytes + * for the next match, plus minMatch bytes to insert the + * string following the next match. + */ + if(lookahead_ < kMinLookahead) + { + fill_window(zs); + if(lookahead_ < kMinLookahead && flush == Flush::none) + return need_more; + if(lookahead_ == 0) + break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0; + if(lookahead_ >= minMatch) { + insert_string(hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < minMatch + */ + if(hash_head != 0 && strstart_ - hash_head <= max_dist()) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + match_length_ = longest_match (hash_head); + /* longest_match() sets match_start */ + } + if(match_length_ >= minMatch) + { + tr_tally_dist(strstart_ - match_start_, + match_length_ - minMatch, bflush); + + lookahead_ -= match_length_; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if(match_length_ <= max_lazy_match_ && + lookahead_ >= minMatch) { + match_length_--; /* string at strstart already in table */ + do + { + strstart_++; + insert_string(hash_head); + /* strstart never exceeds WSIZE-maxMatch, so there are + * always minMatch bytes ahead. + */ + } + while(--match_length_ != 0); + strstart_++; + } + else + { + strstart_ += match_length_; + match_length_ = 0; + ins_h_ = window_[strstart_]; + update_hash(ins_h_, window_[strstart_+1]); + /* If lookahead < minMatch, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } + else + { + /* No match, output a literal byte */ + tr_tally_lit(window_[strstart_], bflush); + lookahead_--; + strstart_++; + } + if(bflush) + { + flush_block(zs, false); + if(zs.avail_out == 0) + return need_more; + } + } + insert_ = strstart_ < minMatch-1 ? strstart_ : minMatch-1; + if(flush == Flush::finish) + { + flush_block(zs, true); + if(zs.avail_out == 0) + return finish_started; + return finish_done; + } + if(last_lit_) + { + flush_block(zs, false); + if(zs.avail_out == 0) + return need_more; + } + return block_done; +} + +/* Same as above, but achieves better compression. We use a lazy + evaluation for matches: a match is finally adopted only if there is + no better match at the next window position. +*/ +template +inline +auto +deflate_stream:: +f_slow(z_params& zs, Flush flush) -> + block_state +{ + IPos hash_head; /* head of hash chain */ + bool bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for(;;) + { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need maxMatch bytes + * for the next match, plus minMatch bytes to insert the + * string following the next match. + */ + if(lookahead_ < kMinLookahead) + { + fill_window(zs); + if(lookahead_ < kMinLookahead && flush == Flush::none) + return need_more; + if(lookahead_ == 0) + break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = 0; + if(lookahead_ >= minMatch) + insert_string(hash_head); + + /* Find the longest match, discarding those <= prev_length. + */ + prev_length_ = match_length_, prev_match_ = match_start_; + match_length_ = minMatch-1; + + if(hash_head != 0 && prev_length_ < max_lazy_match_ && + strstart_ - hash_head <= max_dist()) + { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + match_length_ = longest_match(hash_head); + /* longest_match() sets match_start */ + + if(match_length_ <= 5 && (strategy_ == Strategy::filtered + || (match_length_ == minMatch && + strstart_ - match_start_ > kTooFar) + )) + { + /* If prev_match is also minMatch, match_start is garbage + * but we will ignore the current match anyway. + */ + match_length_ = minMatch-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if(prev_length_ >= minMatch && match_length_ <= prev_length_) + { + /* Do not insert strings in hash table beyond this. */ + uInt max_insert = strstart_ + lookahead_ - minMatch; + + tr_tally_dist(strstart_ -1 - prev_match_, + prev_length_ - minMatch, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + lookahead_ -= prev_length_-1; + prev_length_ -= 2; + do { + if(++strstart_ <= max_insert) + insert_string(hash_head); + } + while(--prev_length_ != 0); + match_available_ = 0; + match_length_ = minMatch-1; + strstart_++; + + if(bflush) + { + flush_block(zs, false); + if(zs.avail_out == 0) + return need_more; + } + + } + else if(match_available_) + { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + tr_tally_lit(window_[strstart_-1], bflush); + if(bflush) + flush_block(zs, false); + strstart_++; + lookahead_--; + if(zs.avail_out == 0) + return need_more; + } + else + { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + match_available_ = 1; + strstart_++; + lookahead_--; + } + } + BOOST_ASSERT(flush != Flush::none); + if(match_available_) + { + tr_tally_lit(window_[strstart_-1], bflush); + match_available_ = 0; + } + insert_ = strstart_ < minMatch-1 ? strstart_ : minMatch-1; + if(flush == Flush::finish) + { + flush_block(zs, true); + if(zs.avail_out == 0) + return finish_started; + return finish_done; + } + if(last_lit_) + { + flush_block(zs, false); + if(zs.avail_out == 0) + return need_more; + } + return block_done; +} + +/* For Strategy::rle, simply look for runs of bytes, generate matches only of distance + one. Do not maintain a hash table. (It will be regenerated if this run of + deflate switches away from Strategy::rle.) +*/ +template +inline +auto +deflate_stream:: +f_rle(z_params& zs, Flush flush) -> + block_state +{ + bool bflush; // set if current block must be flushed + uInt prev; // byte at distance one to match + Byte *scan, *strend; // scan goes up to strend for length of run + + for(;;) + { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need maxMatch bytes + * for the longest run, plus one for the unrolled loop. + */ + if(lookahead_ <= maxMatch) { + fill_window(zs); + if(lookahead_ <= maxMatch && flush == Flush::none) { + return need_more; + } + if(lookahead_ == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + match_length_ = 0; + if(lookahead_ >= minMatch && strstart_ > 0) { + scan = window_ + strstart_ - 1; + prev = *scan; + if(prev == *++scan && prev == *++scan && prev == *++scan) { + strend = window_ + strstart_ + maxMatch; + do { + } while(prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + scan < strend); + match_length_ = maxMatch - (int)(strend - scan); + if(match_length_ > lookahead_) + match_length_ = lookahead_; + } + BOOST_ASSERT(scan <= window_+(uInt)(window_size_-1)); + } + + /* Emit match if have run of minMatch or longer, else emit literal */ + if(match_length_ >= minMatch) { + tr_tally_dist(1, match_length_ - minMatch, bflush); + + lookahead_ -= match_length_; + strstart_ += match_length_; + match_length_ = 0; + } else { + /* No match, output a literal byte */ + tr_tally_lit(window_[strstart_], bflush); + lookahead_--; + strstart_++; + } + if(bflush) + { + flush_block(zs, false); + if(zs.avail_out == 0) + return need_more; + } + } + insert_ = 0; + if(flush == Flush::finish) + { + flush_block(zs, true); + if(zs.avail_out == 0) + return finish_started; + return finish_done; + } + if(last_lit_) + { + flush_block(zs, false); + if(zs.avail_out == 0) + return need_more; + } + return block_done; +} + +/* =========================================================================== + * For Strategy::huffman, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +template +inline +auto +deflate_stream:: +f_huff(z_params& zs, Flush flush) -> + block_state +{ + bool bflush; // set if current block must be flushed + + for(;;) + { + // Make sure that we have a literal to write. + if(lookahead_ == 0) + { + fill_window(zs); + if(lookahead_ == 0) + { + if(flush == Flush::none) + return need_more; + break; // flush the current block + } + } + + // Output a literal byte + match_length_ = 0; + tr_tally_lit(window_[strstart_], bflush); + lookahead_--; + strstart_++; + if(bflush) + { + flush_block(zs, false); + if(zs.avail_out == 0) + return need_more; + } + } + insert_ = 0; + if(flush == Flush::finish) + { + flush_block(zs, true); + if(zs.avail_out == 0) + return finish_started; + return finish_done; + } + if(last_lit_) + { + flush_block(zs, false); + if(zs.avail_out == 0) + return need_more; + } + return block_done; +} + +} // detail +} // zlib +} // beast + +#endif diff --git a/include/beast/zlib/detail/inflate_stream.hpp b/include/beast/zlib/detail/inflate_stream.hpp new file mode 100644 index 000000000..c13d9428c --- /dev/null +++ b/include/beast/zlib/detail/inflate_stream.hpp @@ -0,0 +1,1302 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This is a derivative work based on Zlib, copyright below: +/* + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef BEAST_ZLIB_DETAIL_INFLATE_STREAM_HPP +#define BEAST_ZLIB_DETAIL_INFLATE_STREAM_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace beast { +namespace zlib { +namespace detail { + +class inflate_stream +{ +protected: + inflate_stream() + { + w_.reset(15); + } + + template void doClear(); + template void doReset(int windowBits); + template void doWrite(z_params& zs, Flush flush, error_code& ec); + + void + doReset() + { + doReset(w_.bits()); + } + +private: + enum Mode + { + HEAD, // i: waiting for magic header + FLAGS, // i: waiting for method and flags (gzip) + TIME, // i: waiting for modification time (gzip) + OS, // i: waiting for extra flags and operating system (gzip) + EXLEN, // i: waiting for extra length (gzip) + EXTRA, // i: waiting for extra bytes (gzip) + NAME, // i: waiting for end of file name (gzip) + COMMENT, // i: waiting for end of comment (gzip) + HCRC, // i: waiting for header crc (gzip) + TYPE, // i: waiting for type bits, including last-flag bit + TYPEDO, // i: same, but skip check to exit inflate on new block + STORED, // i: waiting for stored size (length and complement) + COPY_, // i/o: same as COPY below, but only first time in + COPY, // i/o: waiting for input or output to copy stored block + TABLE, // i: waiting for dynamic block table lengths + LENLENS, // i: waiting for code length code lengths + CODELENS, // i: waiting for length/lit and distance code lengths + LEN_, // i: same as LEN below, but only first time in + LEN, // i: waiting for length/lit/eob code + LENEXT, // i: waiting for length extra bits + DIST, // i: waiting for distance code + DISTEXT,// i: waiting for distance extra bits + MATCH, // o: waiting for output space to copy string + LIT, // o: waiting for output space to write literal + CHECK, // i: waiting for 32-bit check value + LENGTH, // i: waiting for 32-bit length (gzip) + DONE, // finished check, done -- remain here until reset + BAD, // got a data error -- remain here until reset + SYNC // looking for synchronization bytes to restart inflate() + }; + + /* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. + + op values as set by inflate_table(): + + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + struct code + { + std::uint8_t op; // operation, extra bits, table bits + std::uint8_t bits; // bits in this part of the code + std::uint16_t val; // offset in table or code value + }; + + /* Maximum size of the dynamic table. The maximum number of code + structures is 1444, which is the sum of 852 for literal/length codes + and 592 for distance codes. These values were found by exhaustive + searches using the program examples/enough.c found in the zlib + distribtution. The arguments to that program are the number of + symbols, the initial root table size, and the maximum bit length + of a code. "enough 286 9 15" for literal/length codes returns + returns 852, and "enough 30 6 15" for distance codes returns 592. + The initial root table size (9 or 6) is found in the fifth argument + of the inflate_table() calls in inflate.c and infback.c. If the + root table size is changed, then these maximum sizes would be need + to be recalculated and updated. + */ + static std::uint16_t constexpr kEnoughLens = 852; + static std::uint16_t constexpr kEnoughDists = 592; + static std::uint16_t constexpr kEnough = kEnoughLens + kEnoughDists; + + struct codes + { + code const* lencode; + code const* distcode; + unsigned lenbits; // VFALCO use std::uint8_t + unsigned distbits; + }; + + // Type of code to build for inflate_table() + enum class build + { + codes, + lens, + dists + }; + + template + static + void + inflate_table( + build type, + std::uint16_t* lens, + std::size_t codes, + code** table, + unsigned *bits, + std::uint16_t* work, + error_code& ec); + + template + static + codes const& + get_fixed_tables(); + + template + void + fixedTables(); + + template + void + inflate_fast(ranges& r, error_code& ec); + + bitstream bi_; + + Mode mode_ = HEAD; // current inflate mode + int last_ = 0; // true if processing last block + unsigned dmax_ = 32768U; // zlib header max distance (INFLATE_STRICT) + + // sliding window + window w_; + + // for string and stored block copying + unsigned length_; // literal or length of data to copy + unsigned offset_; // distance back to copy string from + + // for table and code decoding + unsigned extra_; // extra bits needed + + // dynamic table building + unsigned ncode_; // number of code length code lengths + unsigned nlen_; // number of length code lengths + unsigned ndist_; // number of distance code lengths + unsigned have_; // number of code lengths in lens[] + unsigned short lens_[320]; // temporary storage for code lengths + unsigned short work_[288]; // work area for code table building + code codes_[kEnough]; // space for code tables + code *next_ = codes_; // next available space in codes[] + int back_ = -1; // bits back of last unprocessed length/lit + unsigned was_; // initial length of match + + // fixed and dynamic code tables + code const* lencode_ = codes_ ; // starting table for length/literal codes + code const* distcode_ = codes_; // starting table for distance codes + unsigned lenbits_; // index bits for lencode + unsigned distbits_; // index bits for distcode +}; + +//------------------------------------------------------------------------------ + +template +void +inflate_stream:: +doReset(int windowBits) +{ + if(windowBits < 8 || windowBits > 15) + throw std::domain_error("windowBits out of range"); + w_.reset(windowBits); + + bi_.flush(); + mode_ = HEAD; + last_ = 0; + dmax_ = 32768U; + lencode_ = codes_; + distcode_ = codes_; + next_ = codes_; + back_ = -1; +} + +template +void +inflate_stream:: +doClear() +{ +} + +template +void +inflate_stream:: +doWrite(z_params& zs, Flush flush, error_code& ec) +{ + ranges r; + r.in.first = reinterpret_cast< + std::uint8_t const*>(zs.next_in); + r.in.last = r.in.first + zs.avail_in; + r.in.next = r.in.first; + r.out.first = reinterpret_cast< + std::uint8_t*>(zs.next_out); + r.out.last = r.out.first + zs.avail_out; + r.out.next = r.out.first; + + auto const done = + [&] + { + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + + + // VFALCO TODO Don't allocate update the window unless necessary + if(/*wsize_ ||*/ (r.out.used() && mode_ < BAD && + (mode_ < CHECK || flush != Flush::finish))) + w_.write(r.out.first, r.out.used()); + + zs.next_in = r.in.next; + zs.avail_in = r.in.avail(); + zs.next_out = r.out.next; + zs.avail_out = r.out.avail(); + zs.total_in += r.in.used(); + zs.total_out += r.out.used(); + zs.data_type = bi_.size() + (last_ ? 64 : 0) + + (mode_ == TYPE ? 128 : 0) + + (mode_ == LEN_ || mode_ == COPY_ ? 256 : 0); + + if(((! r.in.used() && ! r.out.used()) || + flush == Flush::finish) && ! ec) + ec = error::need_buffers; + }; + auto const err = + [&](error e) + { + ec = e; + mode_ = BAD; + }; + + if(mode_ == TYPE) + mode_ = TYPEDO; + + for(;;) + { + switch(mode_) + { + case HEAD: + mode_ = TYPEDO; + break; + + case TYPE: + if(flush == Flush::block || flush == Flush::trees) + return done(); + // fall through + + case TYPEDO: + { + if(last_) + { + bi_.flush_byte(); + mode_ = CHECK; + break; + } + if(! bi_.fill(3, r.in.next, r.in.last)) + return done(); + std::uint8_t v; + bi_.read(v, 1); + last_ = v != 0; + bi_.read(v, 2); + switch(v) + { + case 0: + // uncompressed block + mode_ = STORED; + break; + case 1: + // fixed Huffman table + fixedTables(); + mode_ = LEN_; /* decode codes */ + if(flush == Flush::trees) + return done(); + break; + case 2: + // dynamic Huffman table + mode_ = TABLE; + break; + + default: + return err(error::invalid_block_type); + } + break; + } + + case STORED: + { + bi_.flush_byte(); + std::uint32_t v; + if(! bi_.fill(32, r.in.next, r.in.last)) + return done(); + bi_.peek(v, 32); + length_ = v & 0xffff; + if(length_ != ((v >> 16) ^ 0xffff)) + return err(error::invalid_stored_length); + // flush instead of read, otherwise + // undefined right shift behavior. + bi_.flush(); + mode_ = COPY_; + if(flush == Flush::trees) + return done(); + // fall through + } + + case COPY_: + mode_ = COPY; + // fall through + + case COPY: + { + auto copy = length_; + if(copy == 0) + { + mode_ = TYPE; + break; + } + copy = clamp(copy, r.in.avail()); + copy = clamp(copy, r.out.avail()); + if(copy == 0) + return done(); + std::memcpy(r.out.next, r.in.next, copy); + r.in.next += copy; + r.out.next += copy; + length_ -= copy; + break; + } + + case TABLE: + if(! bi_.fill(5 + 5 + 4, r.in.next, r.in.last)) + return done(); + bi_.read(nlen_, 5); + nlen_ += 257; + bi_.read(ndist_, 5); + ndist_ += 1; + bi_.read(ncode_, 4); + ncode_ += 4; + if(nlen_ > 286 || ndist_ > 30) + return err(error::too_many_symbols); + have_ = 0; + mode_ = LENLENS; + // fall through + + case LENLENS: + { + static std::array constexpr order = {{ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}}; + while(have_ < ncode_) + { + if(! bi_.fill(3, r.in.next, r.in.last)) + return done(); + bi_.read(lens_[order[have_]], 3); + ++have_; + } + while(have_ < order.size()) + lens_[order[have_++]] = 0; + + next_ = &codes_[0]; + lencode_ = next_; + lenbits_ = 7; + inflate_table(build::codes, &lens_[0], + order.size(), &next_, &lenbits_, work_, ec); + if(ec) + { + mode_ = BAD; + break; + } + have_ = 0; + mode_ = CODELENS; + // fall through + } + + case CODELENS: + { + while(have_ < nlen_ + ndist_) + { + std::uint16_t v; + if(! bi_.fill(lenbits_, r.in.next, r.in.last)) + return done(); + bi_.peek(v, lenbits_); + auto cp = &lencode_[v]; + if(cp->val < 16) + { + bi_.drop(cp->bits); + lens_[have_++] = cp->val; + } + else + { + std::uint16_t len; + std::uint16_t copy; + if(cp->val == 16) + { + if(! bi_.fill(cp->bits + 2, r.in.next, r.in.last)) + return done(); + bi_.drop(cp->bits); + if(have_ == 0) + return err(error::invalid_bit_length_repeat); + bi_.read(copy, 2); + len = lens_[have_ - 1]; + copy += 3; + + } + else if(cp->val == 17) + { + if(! bi_.fill(cp->bits + 3, r.in.next, r.in.last)) + return done(); + bi_.drop(cp->bits); + bi_.read(copy, 3); + len = 0; + copy += 3; + } + else + { + if(! bi_.fill(cp->bits + 7, r.in.next, r.in.last)) + return done(); + bi_.drop(cp->bits); + bi_.read(copy, 7); + len = 0; + copy += 11; + } + if(have_ + copy > nlen_ + ndist_) + return err(error::invalid_bit_length_repeat); + std::fill(&lens_[have_], &lens_[have_ + copy], len); + have_ += copy; + copy = 0; + } + } + // handle error breaks in while + if(mode_ == BAD) + break; + // check for end-of-block code (better have one) + if(lens_[256] == 0) + return err(error::missing_eob); + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.hpp + concerning the kEnough constants, which depend on those values */ + next_ = &codes_[0]; + lencode_ = next_; + lenbits_ = 9; + inflate_table(build::lens, &lens_[0], + nlen_, &next_, &lenbits_, work_, ec); + if(ec) + { + mode_ = BAD; + return; + } + distcode_ = next_; + distbits_ = 6; + inflate_table(build::dists, lens_ + nlen_, + ndist_, &next_, &distbits_, work_, ec); + if(ec) + { + mode_ = BAD; + return; + } + mode_ = LEN_; + if(flush == Flush::trees) + return done(); + // fall through + } + + case LEN_: + mode_ = LEN; + // fall through + + case LEN: + { + if(r.in.avail() >= 6 && r.out.avail() >= 258) + { + inflate_fast(r, ec); + if(ec) + { + mode_ = BAD; + return; + } + if(mode_ == TYPE) + back_ = -1; + break; + } + if(! bi_.fill(lenbits_, r.in.next, r.in.last)) + return done(); + std::uint16_t v; + back_ = 0; + bi_.peek(v, lenbits_); + auto cp = &lencode_[v]; + if(cp->op && (cp->op & 0xf0) == 0) + { + auto prev = cp; + if(! bi_.fill(prev->bits + prev->op, r.in.next, r.in.last)) + return done(); + bi_.peek(v, prev->bits + prev->op); + cp = &lencode_[prev->val + (v >> prev->bits)]; + bi_.drop(prev->bits + cp->bits); + back_ += prev->bits + cp->bits; + } + else + { + bi_.drop(cp->bits); + back_ += cp->bits; + } + length_ = cp->val; + if(cp->op == 0) + { + mode_ = LIT; + break; + } + if(cp->op & 32) + { + back_ = -1; + mode_ = TYPE; + break; + } + if(cp->op & 64) + return err(error::invalid_literal_length); + extra_ = cp->op & 15; + mode_ = LENEXT; + // fall through + } + + case LENEXT: + if(extra_) + { + if(! bi_.fill(extra_, r.in.next, r.in.last)) + return done(); + std::uint16_t v; + bi_.read(v, extra_); + length_ += v; + back_ += extra_; + } + was_ = length_; + mode_ = DIST; + // fall through + + case DIST: + { + if(! bi_.fill(distbits_, r.in.next, r.in.last)) + return done(); + std::uint16_t v; + bi_.peek(v, distbits_); + auto cp = &distcode_[v]; + if((cp->op & 0xf0) == 0) + { + auto prev = cp; + if(! bi_.fill(prev->bits + prev->op, r.in.next, r.in.last)) + return done(); + bi_.peek(v, prev->bits + prev->op); + cp = &distcode_[prev->val + (v >> prev->bits)]; + bi_.drop(prev->bits + cp->bits); + back_ += prev->bits + cp->bits; + } + else + { + bi_.drop(cp->bits); + back_ += cp->bits; + } + if(cp->op & 64) + return err(error::invalid_distance_code); + offset_ = cp->val; + extra_ = cp->op & 15; + mode_ = DISTEXT; + // fall through + } + + case DISTEXT: + if(extra_) + { + std::uint16_t v; + if(! bi_.fill(extra_, r.in.next, r.in.last)) + return done(); + bi_.read(v, extra_); + offset_ += v; + back_ += extra_; + } +#ifdef INFLATE_STRICT + if(offset_ > dmax_) + return err(error::invalid_distance); +#endif + mode_ = MATCH; + // fall through + + case MATCH: + { + if(! r.out.avail()) + return done(); + if(offset_ > r.out.used()) + { + // copy from window + auto offset = static_cast( + offset_ - r.out.used()); + if(offset > w_.size()) + return err(error::invalid_distance); + auto const n = clamp(clamp( + length_, offset), r.out.avail()); + w_.read(r.out.next, offset, n); + r.out.next += n; + length_ -= n; + } + else + { + // copy from output + auto in = r.out.next - offset_; + auto n = clamp(length_, r.out.avail()); + length_ -= n; + while(n--) + *r.out.next++ = *in++; + } + if(length_ == 0) + mode_ = LEN; + break; + } + + case LIT: + { + if(! r.out.avail()) + return done(); + auto const v = static_cast(length_); + *r.out.next++ = v; + mode_ = LEN; + break; + } + + case CHECK: + mode_ = DONE; + // fall through + + case DONE: + ec = error::end_of_stream; + return done(); + + case BAD: + return done(); + + case SYNC: + default: + throw std::logic_error("stream error"); + } + } +} + +//------------------------------------------------------------------------------ + +/* Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, build::codes, build::lens, or build::dists. On + return, zero is success, -1 is an invalid code, and +1 means that + kEnough isn't enough. table on return points to the next available + entry's address. bits is the requested root table index bits, and + on return it is the actual root table index bits. It will differ if + the request is greater than the longest code or if it is less than + the shortest code. +*/ +template +void +inflate_stream:: +inflate_table( + build type, + std::uint16_t* lens, + std::size_t codes, + code** table, + unsigned *bits, + std::uint16_t* work, + error_code& ec) +{ + unsigned len; // a code's length in bits + unsigned sym; // index of code symbols + unsigned min, max; // minimum and maximum code lengths + unsigned root; // number of index bits for root table + unsigned curr; // number of index bits for current table + unsigned drop; // code bits to drop for sub-table + int left; // number of prefix codes available + unsigned used; // code entries in table used + unsigned huff; // Huffman code + unsigned incr; // for incrementing code, index + unsigned fill; // index for replicating entries + unsigned low; // low bits for current root entry + unsigned mask; // mask for low root bits + code here; // table entry for duplication + code *next; // next available space in table + std::uint16_t const* base; // base value table to use + std::uint16_t const* extra; // extra bits table to use + int end; // use base and extra for symbol > end + std::uint16_t count[15+1]; // number of codes of each length + std::uint16_t offs[15+1]; // offsets in table for each length + + // Length codes 257..285 base + static std::uint16_t constexpr lbase[31] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + + // Length codes 257..285 extra + static std::uint16_t constexpr lext[31] = { + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78}; + + // Distance codes 0..29 base + static std::uint16_t constexpr dbase[32] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + + // Distance codes 0..29 extra + static std::uint16_t constexpr dext[32] = { + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..15. The caller must assure this. + 1..15 is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..15) */ + for (len = 0; len <= 15; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = 15; max >= 1; max--) + if (count[max] != 0) + break; + if (root > max) + root = max; + if (max == 0) + { /* no symbols to code at all */ + here.op = (std::uint8_t)64; /* invalid code marker */ + here.bits = (std::uint8_t)1; + here.val = (std::uint16_t)0; + *(*table)++ = here; /* make a table to force an error */ + *(*table)++ = here; + *bits = 1; + return; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) + if (count[min] != 0) + break; + if (root < min) + root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= 15; len++) + { + left <<= 1; + left -= count[len]; + if (left < 0) + { + ec = error::over_subscribed_length; + return; + } + } + if (left > 0 && (type == build::codes || max != 1)) + { + ec = error::incomplete_length_set; + return; + } + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < 15; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) + work[offs[lens[sym]]++] = (std::uint16_t)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for build::lens and DIST tables against + the constants kEnoughLens and kEnoughDists to guard against changes in + the initial root table size constants. See the comments in inftrees.hpp + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) + { + case build::codes: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case build::lens: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* build::dists */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + auto const not_enough = [] + { + throw std::logic_error( + "insufficient output size when inflating tables"); + }; + + // check available table space + if ((type == build::lens && used > kEnoughLens) || + (type == build::dists && used > kEnoughDists)) + return not_enough(); + + /* process all codes and make table entries */ + for (;;) + { + /* create table entry */ + here.bits = (std::uint8_t)(len - drop); + if ((int)(work[sym]) < end) + { + here.op = (std::uint8_t)0; + here.val = work[sym]; + } + else if ((int)(work[sym]) > end) + { + here.op = (std::uint8_t)(extra[work[sym]]); + here.val = base[work[sym]]; + } + else + { + here.op = (std::uint8_t)(32 + 64); /* end of block */ + here.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do + { + fill -= incr; + next[(huff >> drop) + fill] = here; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) + { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) + { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) + { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) + { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == build::lens && used > kEnoughLens) || + (type == build::dists && used > kEnoughDists)) + return not_enough(); + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (std::uint8_t)curr; + (*table)[low].bits = (std::uint8_t)root; + (*table)[low].val = (std::uint16_t)(next - *table); + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff != 0) + { + here.op = 64; // invalid code marker + here.bits = (std::uint8_t)(len - drop); + here.val = 0; + next[huff] = here; + } + + *table += used; + *bits = root; +} + +template +auto +inflate_stream:: +get_fixed_tables() -> + codes const& +{ + struct fixed_codes : codes + { + code len_[512]; + code dist_[32]; + + fixed_codes() + { + lencode = len_; + lenbits = 9; + distcode = dist_; + distbits = 5; + + std::uint16_t lens[320]; + std::uint16_t work[288]; + + std::fill(&lens[ 0], &lens[144], 8); + std::fill(&lens[144], &lens[256], 9); + std::fill(&lens[256], &lens[280], 7); + std::fill(&lens[280], &lens[288], 8); + + { + error_code ec; + auto next = &len_[0]; + inflate_table(build::lens, + lens, 288, &next, &lenbits, work, ec); + if(ec) + throw std::logic_error{ec.message()}; + } + + // VFALCO These fixups are from ZLib + len_[ 99].op = 64; + len_[227].op = 64; + len_[355].op = 64; + len_[483].op = 64; + + { + error_code ec; + auto next = &dist_[0]; + std::fill(&lens[0], &lens[32], 5); + inflate_table(build::dists, + lens, 32, &next, &distbits, work, ec); + if(ec) + throw std::logic_error{ec.message()}; + } + } + }; + + static fixed_codes const fc; + return fc; +} + +template +void +inflate_stream:: +fixedTables() +{ + auto const fc = get_fixed_tables(); + lencode_ = fc.lencode; + lenbits_ = fc.lenbits; + distcode_ = fc.distcode; + distbits_ = fc.distbits; +} + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode_ == LEN + zs.avail_in >= 6 + zs.avail_out >= 258 + start >= zs.avail_out + state->bits_ < 8 + + On return, state->mode_ is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if zs.avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires zs.avail_out >= 258 for each loop to avoid checking for + output space. + + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ +template +void +inflate_stream:: +inflate_fast(ranges& r, error_code& ec) +{ + unsigned char const* last; // have enough input while in < last + unsigned char *end; // while out < end, enough space available + std::size_t op; // code bits, operation, extra bits, or window position, window bytes to copy + unsigned len; // match length, unused bytes + unsigned dist; // match distance + unsigned const lmask = + (1U << lenbits_) - 1; // mask for first level of length codes + unsigned const dmask = + (1U << distbits_) - 1; // mask for first level of distance codes + + last = r.in.next + (r.in.avail() - 5); + end = r.out.next + (r.out.avail() - 257); + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do + { + if(bi_.size() < 15) + bi_.fill_16(r.in.next); + auto cp = &lencode_[bi_.peek_fast() & lmask]; + dolen: + bi_.drop(cp->bits); + op = (unsigned)(cp->op); + if(op == 0) + { + // literal + *r.out.next++ = (unsigned char)(cp->val); + } + else if(op & 16) + { + // length base + len = (unsigned)(cp->val); + op &= 15; // number of extra bits + if(op) + { + if(bi_.size() < op) + bi_.fill_8(r.in.next); + len += (unsigned)bi_.peek_fast() & ((1U << op) - 1); + bi_.drop(op); + } + if(bi_.size() < 15) + bi_.fill_16(r.in.next); + cp = &distcode_[bi_.peek_fast() & dmask]; + dodist: + bi_.drop(cp->bits); + op = (unsigned)(cp->op); + if(op & 16) + { + // distance base + dist = (unsigned)(cp->val); + op &= 15; // number of extra bits + if(bi_.size() < op) + { + bi_.fill_8(r.in.next); + if(bi_.size() < op) + bi_.fill_8(r.in.next); + } + dist += (unsigned)bi_.peek_fast() & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if(dist > dmax_) + { + ec = error::invalid_distance; + mode_ = BAD; + break; + } +#endif + bi_.drop(op); + + op = r.out.used(); + if(dist > op) + { + // copy from window + op = dist - op; // distance back in window + if(op > w_.size()) + { + ec = error::invalid_distance; + mode_ = BAD; + break; + } + auto const n = clamp(len, op); + w_.read(r.out.next, op, n); + r.out.next += n; + len -= n; + } + if(len > 0) + { + // copy from output + auto in = r.out.next - dist; + auto n = clamp(len, r.out.avail()); + len -= n; + while(n--) + *r.out.next++ = *in++; + } + } + else if((op & 64) == 0) + { + // 2nd level distance code + cp = &distcode_[cp->val + (bi_.peek_fast() & ((1U << op) - 1))]; + goto dodist; + } + else + { + ec = error::invalid_distance_code; + mode_ = BAD; + break; + } + } + else if((op & 64) == 0) + { + // 2nd level length code + cp = &lencode_[cp->val + (bi_.peek_fast() & ((1U << op) - 1))]; + goto dolen; + } + else if(op & 32) + { + // end-of-block + mode_ = TYPE; + break; + } + else + { + ec = error::invalid_literal_length; + mode_ = BAD; + break; + } + } + while(r.in.next < last && r.out.next < end); + + // return unused bytes (on entry, bits < 8, so in won't go too far back) + bi_.rewind(r.in.next); +} + +} // detail +} // zlib +} // beast + +#endif diff --git a/include/beast/zlib/detail/ranges.hpp b/include/beast/zlib/detail/ranges.hpp new file mode 100644 index 000000000..045a4dc6d --- /dev/null +++ b/include/beast/zlib/detail/ranges.hpp @@ -0,0 +1,100 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This is a derivative work based on Zlib, copyright below: +/* + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef BEAST_ZLIB_DETAIL_RANGES_HPP +#define BEAST_ZLIB_DETAIL_RANGES_HPP + +#include +#include + +namespace beast { +namespace zlib { +namespace detail { + +struct ranges +{ + template + struct range + { + using iter_t = + typename std::conditional::type; + + iter_t first; + iter_t last; + iter_t next; + + // total bytes in range + std::size_t + size() const + { + return last - first; + } + + // bytes consumed + std::size_t + used() const + { + return next - first; + } + + // bytes remaining + std::size_t + avail() const + { + return last - next; + } + }; + + range in; + range out; +}; + +// Clamp u to v where u and v are different types +template +inline +U +clamp(U u, V v) +{ + if(u > v) + u = static_cast(v); + return u; +} + +} // detail +} // zlib +} // beast + +#endif diff --git a/include/beast/zlib/detail/window.hpp b/include/beast/zlib/detail/window.hpp new file mode 100644 index 000000000..8fe1e6efc --- /dev/null +++ b/include/beast/zlib/detail/window.hpp @@ -0,0 +1,161 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This is a derivative work based on Zlib, copyright below: +/* + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef BEAST_ZLIB_DETAIL_WINDOW_HPP +#define BEAST_ZLIB_DETAIL_WINDOW_HPP + +#include +#include +#include +#include + +namespace beast { +namespace zlib { +namespace detail { + +class window +{ + std::unique_ptr p_; + std::uint16_t i_ = 0; + std::uint16_t size_ = 0; + std::uint16_t capacity_ = 0; + std::uint8_t bits_ = 0; + +public: + int + bits() const + { + return bits_; + } + + unsigned + capacity() const + { + return capacity_; + } + + unsigned + size() const + { + return size_; + } + + void + reset(int bits); + + void + read(std::uint8_t* out, std::size_t pos, std::size_t n); + + template + void + write(std::uint8_t const* in, std::size_t n); +}; + +inline +void +window:: +reset(int bits) +{ + if(bits_ != bits) + { + p_.reset(); + bits_ = static_cast(bits); + capacity_ = 1U << bits_; + } + i_ = 0; + size_ = 0; +} + +inline +void +window:: +read(std::uint8_t* out, std::size_t pos, std::size_t n) +{ + if(i_ >= size_) + { + // window is contiguous + std::memcpy(out, &p_[i_ - pos], n); + return; + } + auto i = ((i_ - pos) + capacity_) % capacity_; + auto m = capacity_ - i; + if(n <= m) + { + std::memcpy(out, &p_[i], n); + return; + } + std::memcpy(out, &p_[i], m); + out += m; + std::memcpy(out, &p_[0], n - m); +} + +template +void +window:: +write(std::uint8_t const* in, std::size_t n) +{ + if(! p_) + p_.reset(new std::uint8_t[capacity_]); + if(n >= capacity_) + { + i_ = 0; + size_ = capacity_; + std::memcpy(&p_[0], in + (n - size_), size_); + return; + } + if(i_ + n <= capacity_) + { + std::memcpy(&p_[i_], in, n); + if(size_ >= capacity_ - n) + size_ = capacity_; + else + size_ = static_cast(size_ + n); + + i_ = static_cast( + (i_ + n) % capacity_); + return; + } + auto m = capacity_ - i_; + std::memcpy(&p_[i_], in, m); + in += m; + i_ = static_cast(n - m); + std::memcpy(&p_[0], in, i_); + size_ = capacity_; +} + +} // detail +} // zlib +} // beast + +#endif diff --git a/include/beast/zlib/error.hpp b/include/beast/zlib/error.hpp new file mode 100644 index 000000000..05864a517 --- /dev/null +++ b/include/beast/zlib/error.hpp @@ -0,0 +1,133 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This is a derivative work based on Zlib, copyright below: +/* + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef BEAST_ZLIB_ERROR_HPP +#define BEAST_ZLIB_ERROR_HPP + +#include + +namespace beast { +namespace zlib { + +/** Error codes returned by the codec. +*/ +enum class error +{ + /** Additional buffers are required. + + This error indicates that one or both of the buffers + provided buffers do not have sufficient available bytes + to make forward progress. + + This does not always indicate a failure condition. + + @note This is the same as `Z_BUF_ERROR` returned by ZLib. + */ + need_buffers = 1, + + /** End of stream reached. + + @note This is the same as `Z_STREAM_END` returned by ZLib. + */ + end_of_stream, + + /** Invalid stream or parameters. + + This error is returned when invalid parameters are passed, + or the operation being performed is not consistent with the + state of the stream. For example, attempting to write data + when the end of stream is already reached. + + @note This is the same as `Z_STREAM_ERROR` returned by ZLib. + */ + stream_error, + + // + // Errors generated by basic_deflate_stream + // + + // + // Errors generated by basic_inflate_stream + // + + /// Invalid block type + invalid_block_type, + + /// Invalid stored block length + invalid_stored_length, + + /// Too many length or distance symbols + too_many_symbols, + + /// Invalid code lengths + invalid_code_lenths, + + /// Invalid bit length repeat + invalid_bit_length_repeat, + + /// Missing end of block code + missing_eob, + + /// Invalid literal/length code + invalid_literal_length, + + /// Invalid distance code + invalid_distance_code, + + /// Invalid distance too far back + invalid_distance, + + // + // Errors generated by inflate_table + // + + /// Over-subscribed length code + over_subscribed_length, + + /// Incomplete length set + incomplete_length_set, + + + + /// general error + general +}; + +} // zlib +} // beast + +#include + +#endif + diff --git a/include/beast/zlib/impl/error.ipp b/include/beast/zlib/impl/error.ipp new file mode 100644 index 000000000..736c8b209 --- /dev/null +++ b/include/beast/zlib/impl/error.ipp @@ -0,0 +1,137 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This is a derivative work based on Zlib, copyright below: +/* + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef BEAST_ZLIB_IMPL_ERROR_IPP +#define BEAST_ZLIB_IMPL_ERROR_IPP + +#include +#include + +namespace boost { +namespace system { +template<> +struct is_error_code_enum +{ + static bool const value = true; +}; +} // system +} // boost + +namespace beast { +namespace zlib { +namespace detail { + +class zlib_error_category : public error_category +{ +public: + const char* + name() const noexcept override + { + return "zlib"; + } + + std::string + message(int ev) const override + { + switch(static_cast(ev)) + { + case error::need_buffers: return "need buffers"; + case error::end_of_stream: return "end of stream"; + case error::stream_error: return "stream error"; + + case error::invalid_block_type: return "invalid block type"; + case error::invalid_stored_length: return "invalid stored block length"; + case error::too_many_symbols: return "too many symbols"; + case error::invalid_code_lenths: return "invalid code lengths"; + case error::invalid_bit_length_repeat: return "invalid bit length repeat"; + case error::missing_eob: return "missing end of block code"; + case error::invalid_literal_length: return "invalid literal/length code"; + case error::invalid_distance_code: return "invalid distance code"; + case error::invalid_distance: return "invalid distance"; + + case error::over_subscribed_length: return "over-subscribed length"; + case error::incomplete_length_set: return "incomplete length set"; + + case error::general: + default: + return "zlib error"; + } + } + + error_condition + default_error_condition(int ev) const noexcept override + { + return error_condition{ev, *this}; + } + + bool + equivalent(int ev, + error_condition const& condition + ) const noexcept override + { + return condition.value() == ev && + &condition.category() == this; + } + + bool + equivalent(error_code const& error, int ev) const noexcept override + { + return error.value() == ev && + &error.category() == this; + } +}; + +inline +error_category const& +get_error_category() +{ + static zlib_error_category const cat{}; + return cat; +} + +} // detail + +inline +error_code +make_error_code(error ev) +{ + return error_code{ + static_cast::type>(ev), + detail::get_error_category()}; +} + +} // zlib +} // beast + +#endif diff --git a/include/beast/zlib/inflate_stream.hpp b/include/beast/zlib/inflate_stream.hpp new file mode 100644 index 000000000..8c9b2166f --- /dev/null +++ b/include/beast/zlib/inflate_stream.hpp @@ -0,0 +1,214 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This is a derivative work based on Zlib, copyright below: +/* + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef BEAST_ZLIB_INFLATE_STREAM_HPP +#define BEAST_ZLIB_INFLATE_STREAM_HPP + +#include + +namespace beast { +namespace zlib { + +/** Raw deflate stream decompressor. + + This implements a raw deflate stream decompressor. The deflate + protocol is a compression protocol described in + "DEFLATE Compressed Data Format Specification version 1.3" + located here: https://tools.ietf.org/html/rfc1951 + + The implementation is a refactored port to C++ of ZLib's "inflate". + A more detailed description of ZLib is at http://zlib.net/. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is memory mapped), or can be done + by repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output (providing + more output space) before each call. +*/ +class inflate_stream + : private detail::inflate_stream +{ +public: + /** Construct a raw deflate decompression stream. + + The window size is set to the default of 15 bits. + */ + inflate_stream() = default; + + /** Reset the stream. + + This puts the stream in a newly constructed state with + the previously specified window size, but without de-allocating + any dynamically created structures. + */ + void + reset() + { + doReset(); + } + + /** Reset the stream. + + This puts the stream in a newly constructed state with the + specified window size, but without de-allocating any dynamically + created structures. + */ + void + reset(int windowBits) + { + doReset(windowBits); + } + + /** Put the stream in a newly constructed state. + + All dynamically allocated memory is de-allocated. + */ + void + clear() + { + doClear(); + } + + /** Decompress input and produce output. + + This function decompresses as much data as possible, and stops when + the input buffer becomes empty or the output buffer becomes full. It + may introduce some output latency (reading input without producing any + output) except when forced to flush. + + One or both of the following actions are performed: + + @li Decompress more input starting at `zs.next_in` and update `zs.next_in` + and `zs.avail_in` accordingly. If not all input can be processed (because + there is not enough room in the output buffer), `zs.next_in` is updated + and processing will resume at this point for the next call. + + @li Provide more output starting at `zs.next_out` and update `zs.next_out` + and `zs.avail_out` accordingly. `write` provides as much output as + possible, until there is no more input data or no more space in the output + buffer (see below about the flush parameter). + + Before the call, the application should ensure that at least one of the + actions is possible, by providing more input and/or consuming more output, + and updating the values in `zs` accordingly. The application can consume + the uncompressed output when it wants, for example when the output buffer + is full (`zs.avail_out == 0`), or after each call. If `write` returns no + error and with zero `zs.avail_out`, it must be called again after making + room in the output buffer because there might be more output pending. + + The flush parameter may be `Flush::none`, `Flush::sync`, `Flush::finish`, + `Flush::block`, or `Flush::trees`. `Flush::sync` requests to flush as much + output as possible to the output buffer. `Flush::block` requests to stop if + and when it gets to the next deflate block boundary. When decoding the + zlib or gzip format, this will cause `write` to return immediately after + the header and before the first block. When doing a raw inflate, `write` will + go ahead and process the first block, and will return when it gets to the + end of that block, or when it runs out of data. + + The `Flush::block` option assists in appending to or combining deflate + streams. Also to assist in this, on return `write` will set `zs.data_type` + to the number of unused bits in the last byte taken from `zs.next_in`, plus + 64 if `write` is currently decoding the last block in the deflate stream, + plus 128 if `write` returned immediately after decoding an end-of-block code + or decoding the complete header up to just before the first byte of the + deflate stream. The end-of-block will not be indicated until all of the + uncompressed data from that block has been written to `zs.next_out`. The + number of unused bits may in general be greater than seven, except when + bit 7 of `zs.data_type` is set, in which case the number of unused bits + will be less than eight. `zs.data_type` is set as noted here every time + `write` returns for all flush options, and so can be used to determine the + amount of currently consumed input in bits. + + The `Flush::trees` option behaves as `Flush::block` does, but it also returns + when the end of each deflate block header is reached, before any actual data + in that block is decoded. This allows the caller to determine the length of + the deflate block header for later use in random access within a deflate block. + 256 is added to the value of `zs.data_type` when `write` returns immediately + after reaching the end of the deflate block header. + + `write` should normally be called until it returns `error::end_of_stream` or + another error. However if all decompression is to be performed in a single + step (a single call of `write`), the parameter flush should be set to + `Flush::finish`. In this case all pending input is processed and all pending + output is flushed; `zs.avail_out` must be large enough to hold all of the + uncompressed data for the operation to complete. (The size of the uncompressed + data may have been saved by the compressor for this purpose.) The use of + `Flush::finish` is not required to perform an inflation in one step. However + it may be used to inform inflate that a faster approach can be used for the + single call. `Flush::finish` also informs inflate to not maintain a sliding + window if the stream completes, which reduces inflate's memory footprint. + If the stream does not complete, either because not all of the stream is + provided or not enough output space is provided, then a sliding window will be + allocated and `write` can be called again to continue the operation as if + `Flush::none` had been used. + + In this implementation, `write` always flushes as much output as possible to + the output buffer, and always uses the faster approach on the first call. So + the effects of the flush parameter in this implementation are on the return value + of `write` as noted below, when `write` returns early when `Flush::block` or + `Flush::trees` is used, and when `write` avoids the allocation of memory for a + sliding window when `Flush::finsih` is used. + + If a preset dictionary is needed after this call (see @ref dictionary below), + `write` sets `zs.adler` to the Adler-32 checksum of the dictionary chosen by + the compressor and returns `error::need_dictionary`; otherwise it sets + `zs.adler` to the Adler-32 checksum of all output produced so far (that is, + `zs.total_out bytes`) and returns no error, `error::end_of_stream`, or an + error code as described below. At the end of the stream, `write` checks that + its computed adler32 checksum is equal to that saved by the compressor and + returns `error::end_of_stream` only if the checksum is correct. + + This function returns no error if some progress has been made (more input + processed or more output produced), `error::end_of_stream` if the end of the + compressed data has been reached and all uncompressed output has been produced, + `error::need_dictionary` if a preset dictionary is needed at this point, + `error::invalid_data` if the input data was corrupted (input stream not + conforming to the zlib format or incorrect check value), `error::stream_error` + if the stream structure was inconsistent (for example if `zs.next_in` or + `zs.next_out` was null), `error::need_buffers` if no progress is possible or + if there was not enough room in the output buffer when `Flush::finish` is + used. Note that `error::need_buffers` is not fatal, and `write` can be called + again with more input and more output space to continue decompressing. + */ + void + write(z_params& zs, Flush flush, error_code& ec) + { + doWrite(zs, flush, ec); + } +}; + +} // zlib +} // beast + +#endif diff --git a/include/beast/zlib/zlib.hpp b/include/beast/zlib/zlib.hpp new file mode 100644 index 000000000..ac5520c7f --- /dev/null +++ b/include/beast/zlib/zlib.hpp @@ -0,0 +1,178 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// This is a derivative work based on Zlib, copyright below: +/* + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef BEAST_ZLIB_ZLIB_HPP +#define BEAST_ZLIB_ZLIB_HPP + +#include +#include + +namespace beast { +namespace zlib { + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ + +/* Possible values of the data_type field (though see inflate()) */ +enum z_Type +{ + Z_BINARY = 0, + Z_TEXT = 1, + Z_UNKNOWN = 2 +}; + +/** Deflate codec parameters. + + Objects of this type are filled in by callers and provided to the + deflate codec to define the input and output areas for the next + compress or decompress operation. + + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use in the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ +struct z_params +{ + /** A pointer to the next input byte. + + If there is no more input, this may be set to `nullptr`. + */ + void const* next_in; + + /** The number of bytes of input available at `next_in`. + + If there is no more input, this should be set to zero. + */ + std::size_t avail_in; + + /** The total number of input bytes read so far. + */ + std::size_t total_in = 0; + + /** A pointer to the next output byte. + */ + void* next_out; + + /** The remaining bytes of space at `next_out`. + */ + std::size_t avail_out; + + /** The total number of bytes output so far. + */ + std::size_t total_out = 0; + + int data_type = Z_UNKNOWN; // best guess about the data type: binary or text +}; + +/** Flush option. +*/ +enum class Flush +{ + // order matters + + none, + block, + partial, + sync, + full, + finish, + trees +}; + +/* compression levels */ +enum z_Compression +{ + Z_NO_COMPRESSION = 0, + Z_BEST_SPEED = 1, + Z_BEST_COMPRESSION = 9, + Z_DEFAULT_COMPRESSION = -1 +}; + +/** Compression strategy. + + These are used when compressing streams. +*/ +enum class Strategy +{ + /** Default strategy. + + This is suitable for general purpose compression, and works + well in the majority of cases. + */ + normal, + + /** Filtered strategy. + + This strategy should be used when the data be compressed + is produced by a filter or predictor. + */ + filtered, + + /** Huffman-only strategy. + + This strategy only performs Huffman encoding, without doing + any string matching. + */ + huffman, + + /** Run Length Encoding strategy. + + This strategy limits match distances to one, making it + equivalent to run length encoding. This can give better + performance for things like PNG image data. + */ + rle, + + /** Fixed table strategy. + + This strategy prevents the use of dynamic Huffman codes, + allowing for a simpler decoder for special applications. + */ + fixed +}; + +} // zlib +} // beast + +#endif + diff --git a/index.html b/index.html new file mode 100644 index 000000000..97143c8d8 --- /dev/null +++ b/index.html @@ -0,0 +1,20 @@ + + + + + +Automatic redirection failed, please go to +doc/html/index.html +
    + +Boost.Beast
    +
    +Copyright (C) 2013-2016 Vinnie Falco
    +
    +Distributed under the Boost Software License, Version 1.0. (See +accompanying file LICENSE_1_0.txt or copy at +http://www.boost.org/LICENSE_1_0.txt)
    +
    +
    + + diff --git a/scripts/build-and-test.sh b/scripts/build-and-test.sh index 3eecf30e0..3c8ed47ef 100755 --- a/scripts/build-and-test.sh +++ b/scripts/build-and-test.sh @@ -70,7 +70,7 @@ function run_tests_with_valgrind { else # TODO --max-stackframe=8388608 # see: https://travis-ci.org/vinniefalco/Beast/jobs/132486245 - valgrind --error-exitcode=1 "$x" + valgrind --suppressions=./scripts/valgrind.supp --error-exitcode=1 "$x" fi done } diff --git a/scripts/valgrind.supp b/scripts/valgrind.supp new file mode 100644 index 000000000..8ad196a38 --- /dev/null +++ b/scripts/valgrind.supp @@ -0,0 +1,10 @@ +{ + zlib_fill_window_no_init + Memcheck:Cond + fun:fill_window +} +{ + beast_fill_window_no_init + Memcheck:Cond + fun:_ZN5beast4zlib6detail14deflate_stream11fill_windowIvEEvRNS0_8z_paramsE +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c2e538637..4a80f6ae7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -12,8 +12,13 @@ add_executable (lib-tests http.cpp version.cpp websocket.cpp + zlib.cpp ) if (NOT WIN32) target_link_libraries(lib-tests ${Boost_LIBRARIES}) endif() + +if (MINGW) + set_target_properties(lib-tests PROPERTIES COMPILE_FLAGS "-Wa,-mbig-obj") +endif() diff --git a/test/Jamfile b/test/Jamfile index 7807972f3..a023b5fd8 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -11,6 +11,7 @@ compile core.cpp : : ; compile http.cpp : : ; compile version.cpp : : ; compile websocket.cpp : : ; +compile zlib.cpp : : ; unit-test core-tests : ../extras/beast/unit_test/main.cpp @@ -20,11 +21,13 @@ unit-test core-tests : core/buffer_cat.cpp core/buffer_concepts.cpp core/buffers_adapter.cpp + core/clamp.cpp core/consuming_buffers.cpp core/dynabuf_readstream.cpp core/error.cpp core/handler_alloc.cpp core/handler_concepts.cpp + core/handler_ptr.cpp core/placeholders.cpp core/prepare_buffers.cpp core/static_streambuf.cpp @@ -42,14 +45,14 @@ unit-test core-tests : unit-test http-tests : ../extras/beast/unit_test/main.cpp http/basic_dynabuf_body.cpp - http/basic_headers.cpp + http/basic_fields.cpp http/basic_parser_v1.cpp - http/body_type.cpp http/concepts.cpp http/empty_body.cpp - http/headers.cpp + http/fields.cpp + http/header_parser_v1.cpp http/message.cpp - http/message_v1.cpp + http/parse.cpp http/parse_error.cpp http/parser_v1.cpp http/read.cpp @@ -77,10 +80,27 @@ unit-test websocket-tests : websocket/teardown.cpp websocket/frame.cpp websocket/mask.cpp - websocket/stream_base.cpp websocket/utf8_checker.cpp ; exe websocket-echo : websocket/websocket_echo.cpp ; + +unit-test zlib-tests : + ../extras/beast/unit_test/main.cpp + zlib/zlib-1.2.8/adler32.c + zlib/zlib-1.2.8/compress.c + zlib/zlib-1.2.8/crc32.c + zlib/zlib-1.2.8/deflate.c + zlib/zlib-1.2.8/infback.c + zlib/zlib-1.2.8/inffast.c + zlib/zlib-1.2.8/inflate.c + zlib/zlib-1.2.8/inftrees.c + zlib/zlib-1.2.8/trees.c + zlib/zlib-1.2.8/uncompr.c + zlib/zlib-1.2.8/zutil.c + zlib/deflate_stream.cpp + zlib/error.cpp + zlib/inflate_stream.cpp + ; diff --git a/test/core/CMakeLists.txt b/test/core/CMakeLists.txt index e6d291cdb..d96d53245 100644 --- a/test/core/CMakeLists.txt +++ b/test/core/CMakeLists.txt @@ -7,6 +7,7 @@ GroupSources(test/core "/") add_executable (core-tests ${BEAST_INCLUDES} ${EXTRAS_INCLUDES} + ${ZLIB_SOURCES} ../../extras/beast/unit_test/main.cpp buffer_test.hpp async_completion.cpp @@ -15,11 +16,13 @@ add_executable (core-tests buffer_cat.cpp buffer_concepts.cpp buffers_adapter.cpp + clamp.cpp consuming_buffers.cpp dynabuf_readstream.cpp error.cpp handler_alloc.cpp handler_concepts.cpp + handler_ptr.cpp placeholders.cpp prepare_buffers.cpp static_streambuf.cpp diff --git a/test/core/basic_streambuf.cpp b/test/core/basic_streambuf.cpp index 9bb79b6a4..00b468dd7 100644 --- a/test/core/basic_streambuf.cpp +++ b/test/core/basic_streambuf.cpp @@ -397,12 +397,12 @@ public: BEAST_EXPECT(to_string(sb.data()) == "x"); } - void testReadSizeHelper() + void testCapacity() { using boost::asio::buffer_size; { - streambuf sb(10); - BEAST_EXPECT(read_size_helper(sb, 0) == 0); + streambuf sb{10}; + BEAST_EXPECT(sb.alloc_size() == 10); BEAST_EXPECT(read_size_helper(sb, 1) == 1); BEAST_EXPECT(read_size_helper(sb, 10) == 10); BEAST_EXPECT(read_size_helper(sb, 20) == 20); @@ -414,33 +414,51 @@ public: } { streambuf sb(1000); - BEAST_EXPECT(read_size_helper(sb, 0) == 0); + BEAST_EXPECT(sb.alloc_size() == 1000); BEAST_EXPECT(read_size_helper(sb, 1) == 1); BEAST_EXPECT(read_size_helper(sb, 1000) == 1000); BEAST_EXPECT(read_size_helper(sb, 2000) == 1000); sb.prepare(3); - BEAST_EXPECT(read_size_helper(sb, 0) == 0); BEAST_EXPECT(read_size_helper(sb, 1) == 1); BEAST_EXPECT(read_size_helper(sb, 1000) == 1000); BEAST_EXPECT(read_size_helper(sb, 2000) == 1000); sb.commit(3); - BEAST_EXPECT(read_size_helper(sb, 0) == 0); BEAST_EXPECT(read_size_helper(sb, 1) == 1); BEAST_EXPECT(read_size_helper(sb, 1000) == 997); BEAST_EXPECT(read_size_helper(sb, 2000) == 997); sb.consume(2); - BEAST_EXPECT(read_size_helper(sb, 0) == 0); BEAST_EXPECT(read_size_helper(sb, 1) == 1); BEAST_EXPECT(read_size_helper(sb, 1000) == 997); BEAST_EXPECT(read_size_helper(sb, 2000) == 997); } { - streambuf sb(2); + streambuf sb{2}; + BEAST_EXPECT(sb.alloc_size() == 2); BEAST_EXPECT(test::buffer_count(sb.prepare(2)) == 1); BEAST_EXPECT(test::buffer_count(sb.prepare(3)) == 2); BEAST_EXPECT(buffer_size(sb.prepare(5)) == 5); BEAST_EXPECT(read_size_helper(sb, 10) == 6); } + { + auto avail = + [](streambuf const& sb) + { + return sb.capacity() - sb.size(); + }; + streambuf sb{100}; + BEAST_EXPECT(sb.alloc_size() == 100); + BEAST_EXPECT(avail(sb) == 0); + sb.prepare(100); + BEAST_EXPECT(avail(sb) == 100); + sb.commit(100); + BEAST_EXPECT(avail(sb) == 0); + sb.consume(100); + BEAST_EXPECT(avail(sb) == 0); + sb.alloc_size(200); + BEAST_EXPECT(sb.alloc_size() == 200); + sb.prepare(1); + BEAST_EXPECT(avail(sb) == 200); + } } void run() override @@ -453,7 +471,7 @@ public: testMatrix(); testIterators(); testOutputStream(); - testReadSizeHelper(); + testCapacity(); } }; diff --git a/test/core/buffer_cat.cpp b/test/core/buffer_cat.cpp index 803d2efcb..413386222 100644 --- a/test/core/buffer_cat.cpp +++ b/test/core/buffer_cat.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include namespace beast { @@ -20,14 +21,65 @@ namespace beast { class buffer_cat_test : public unit_test::suite { public: - template< class Iterator > + template static std::reverse_iterator - make_reverse_iterator( Iterator i ) + make_reverse_iterator(Iterator i) { return std::reverse_iterator(i); } + template + static + std::size_t + bsize1(ConstBufferSequence const& bs) + { + using boost::asio::buffer_size; + std::size_t n = 0; + for(auto it = bs.begin(); it != bs.end(); ++it) + n += buffer_size(*it); + return n; + } + + template + static + std::size_t + bsize2(ConstBufferSequence const& bs) + { + using boost::asio::buffer_size; + std::size_t n = 0; + for(auto it = bs.begin(); it != bs.end(); it++) + n += buffer_size(*it); + return n; + } + + template + static + std::size_t + bsize3(ConstBufferSequence const& bs) + { + using boost::asio::buffer_size; + std::size_t n = 0; + for(auto it = bs.end(); it != bs.begin();) + n += buffer_size(*--it); + return n; + } + + template + static + std::size_t + bsize4(ConstBufferSequence const& bs) + { + using boost::asio::buffer_size; + std::size_t n = 0; + for(auto it = bs.end(); it != bs.begin();) + { + it--; + n += buffer_size(*it); + } + return n; + } + void testBufferCat() { using boost::asio::buffer_size; @@ -48,6 +100,10 @@ public: auto bs = buffer_cat( b1, b2, b3, b4, b5, b6); BEAST_EXPECT(buffer_size(bs) == 10); + BEAST_EXPECT(bsize1(bs) == 10); + BEAST_EXPECT(bsize2(bs) == 10); + BEAST_EXPECT(bsize3(bs) == 10); + BEAST_EXPECT(bsize4(bs) == 10); std::vector v; for(auto iter = make_reverse_iterator(bs.end()); iter != make_reverse_iterator(bs.begin()); ++iter) @@ -55,8 +111,6 @@ public: BEAST_EXPECT(buffer_size(bs) == 10); decltype(bs) bs2(bs); auto bs3(std::move(bs)); - bs = bs2; - bs3 = std::move(bs2); { boost::asio::streambuf sb1, sb2; BEAST_EXPECT(buffer_size(buffer_cat( @@ -110,6 +164,18 @@ public: pass(); } + // decrement iterator + { + auto const rbegin = + make_reverse_iterator(bs.end()); + auto const rend = + make_reverse_iterator(bs.begin()); + std::size_t n = 0; + for(auto it = rbegin; it != rend; ++it) + n += buffer_size(*it); + BEAST_EXPECT(n == 9); + } + try { std::size_t n = 0; @@ -141,6 +207,60 @@ public: void run() override { + using boost::asio::const_buffer; + using boost::asio::const_buffers_1; + using boost::asio::mutable_buffer; + using boost::asio::mutable_buffers_1; + struct user_defined : mutable_buffer + { + }; + + // Check is_all_ConstBufferSequence + static_assert( + detail::is_all_ConstBufferSequence< + const_buffers_1 + >::value, ""); + static_assert( + detail::is_all_ConstBufferSequence< + const_buffers_1, const_buffers_1 + >::value, ""); + static_assert( + detail::is_all_ConstBufferSequence< + mutable_buffers_1 + >::value, ""); + static_assert( + detail::is_all_ConstBufferSequence< + mutable_buffers_1, mutable_buffers_1 + >::value, ""); + static_assert( + detail::is_all_ConstBufferSequence< + const_buffers_1, mutable_buffers_1 + >::value, ""); + static_assert( + ! detail::is_all_ConstBufferSequence< + const_buffers_1, mutable_buffers_1, int + >::value, ""); + + // Ensure that concatenating mutable buffer + // sequences results in a mutable buffer sequence + static_assert(std::is_same< + mutable_buffer, + decltype(buffer_cat( + std::declval(), + std::declval(), + std::declval() + ))::value_type>::value, ""); + + // Ensure that concatenating mixed buffer + // sequences results in a const buffer sequence. + static_assert(std::is_same< + const_buffer, + decltype(buffer_cat( + std::declval(), + std::declval(), + std::declval() + ))::value_type>::value, ""); + testBufferCat(); testIterators(); } diff --git a/test/websocket/stream_base.cpp b/test/core/clamp.cpp similarity index 57% rename from test/websocket/stream_base.cpp rename to test/core/clamp.cpp index 4bba083ef..e63f526b8 100644 --- a/test/websocket/stream_base.cpp +++ b/test/core/clamp.cpp @@ -6,24 +6,22 @@ // // Test that header file is self-contained. -#include +#include #include -#include #include namespace beast { -namespace websocket { namespace detail { -class stream_base_test : public beast::unit_test::suite +class clamp_test : public beast::unit_test::suite { public: void testClamp() { - BEAST_EXPECT(detail::clamp( - std::numeric_limits::max()) == - std::numeric_limits::max()); + BEAST_EXPECT(clamp( + (std::numeric_limits::max)()) == + (std::numeric_limits::max)()); } void run() override @@ -32,9 +30,8 @@ public: } }; -BEAST_DEFINE_TESTSUITE(stream_base,websocket,beast); +BEAST_DEFINE_TESTSUITE(clamp,core,beast); } // detail -} // websocket } // beast diff --git a/test/core/consuming_buffers.cpp b/test/core/consuming_buffers.cpp index 857000722..71630b0a2 100644 --- a/test/core/consuming_buffers.cpp +++ b/test/core/consuming_buffers.cpp @@ -19,6 +19,16 @@ namespace beast { class consuming_buffers_test : public beast::unit_test::suite { public: + template + static + consuming_buffers + consumed_buffers(BufferSequence const& bs, std::size_t n) + { + consuming_buffers cb(bs); + cb.consume(n); + return cb; + } + template static bool diff --git a/test/core/dynabuf_readstream.cpp b/test/core/dynabuf_readstream.cpp index 9f76551e4..a2ff8bc56 100644 --- a/test/core/dynabuf_readstream.cpp +++ b/test/core/dynabuf_readstream.cpp @@ -59,7 +59,7 @@ public: decltype(fs)&, streambuf> srs(fs); srs.buffer().commit(buffer_copy( srs.buffer().prepare(5), buffer("Hello", 5))); - boost::system::error_code ec; + error_code ec; boost::asio::read(srs, buffer(&s[0], s.size()), ec); if(! ec) { @@ -78,7 +78,7 @@ public: srs.capacity(3); srs.buffer().commit(buffer_copy( srs.buffer().prepare(5), buffer("Hello", 5))); - boost::system::error_code ec; + error_code ec; boost::asio::read(srs, buffer(&s[0], s.size()), ec); if(! ec) { @@ -96,7 +96,7 @@ public: decltype(fs)&, streambuf> srs(fs); srs.buffer().commit(buffer_copy( srs.buffer().prepare(5), buffer("Hello", 5))); - boost::system::error_code ec; + error_code ec; boost::asio::async_read( srs, buffer(&s[0], s.size()), do_yield[ec]); if(! ec) @@ -116,7 +116,7 @@ public: srs.capacity(3); srs.buffer().commit(buffer_copy( srs.buffer().prepare(5), buffer("Hello", 5))); - boost::system::error_code ec; + error_code ec; boost::asio::async_read( srs, buffer(&s[0], s.size()), do_yield[ec]); if(! ec) diff --git a/test/core/handler_ptr.cpp b/test/core/handler_ptr.cpp new file mode 100644 index 000000000..8cd2a8d62 --- /dev/null +++ b/test/core/handler_ptr.cpp @@ -0,0 +1,9 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Test that header file is self-contained. +#include diff --git a/test/core/prepare_buffers.cpp b/test/core/prepare_buffers.cpp index eb40d4c49..44debdfa6 100644 --- a/test/core/prepare_buffers.cpp +++ b/test/core/prepare_buffers.cpp @@ -18,6 +18,57 @@ namespace beast { class prepare_buffers_test : public beast::unit_test::suite { public: + template + static + std::size_t + bsize1(ConstBufferSequence const& bs) + { + using boost::asio::buffer_size; + std::size_t n = 0; + for(auto it = bs.begin(); it != bs.end(); ++it) + n += buffer_size(*it); + return n; + } + + template + static + std::size_t + bsize2(ConstBufferSequence const& bs) + { + using boost::asio::buffer_size; + std::size_t n = 0; + for(auto it = bs.begin(); it != bs.end(); it++) + n += buffer_size(*it); + return n; + } + + template + static + std::size_t + bsize3(ConstBufferSequence const& bs) + { + using boost::asio::buffer_size; + std::size_t n = 0; + for(auto it = bs.end(); it != bs.begin();) + n += buffer_size(*--it); + return n; + } + + template + static + std::size_t + bsize4(ConstBufferSequence const& bs) + { + using boost::asio::buffer_size; + std::size_t n = 0; + for(auto it = bs.end(); it != bs.begin();) + { + it--; + n += buffer_size(*it); + } + return n; + } + template static std::string @@ -97,6 +148,10 @@ public: const_buffer{&b[1], 1}, const_buffer{&b[2], 1}}}; auto pb = prepare_buffers(2, bs); + BEAST_EXPECT(bsize1(pb) == 2); + BEAST_EXPECT(bsize2(pb) == 2); + BEAST_EXPECT(bsize3(pb) == 2); + BEAST_EXPECT(bsize4(pb) == 2); std::size_t n = 0; for(auto it = pb.end(); it != pb.begin(); --it) { diff --git a/test/core/streambuf.cpp b/test/core/streambuf.cpp index 08823eb7c..3f46658d3 100644 --- a/test/core/streambuf.cpp +++ b/test/core/streambuf.cpp @@ -7,3 +7,10 @@ // Test that header file is self-contained. #include + +#include +namespace beast { + +static_assert(is_DynamicBuffer::value, ""); + +} // beast diff --git a/test/core/zlib.cpp b/test/core/zlib.cpp new file mode 100644 index 000000000..f18e5c335 --- /dev/null +++ b/test/core/zlib.cpp @@ -0,0 +1,232 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Test that header file is self-contained. +#include +#include + +#include +#include +#include +#include +#include + +namespace beast { +namespace zlib { + +class zlib_test : public beast::unit_test::suite +{ +public: + class buffer + { + std::size_t size_ = 0; + std::size_t capacity_ = 0; + std::unique_ptr p_; + + public: + buffer() = default; + buffer(buffer&&) = default; + buffer& operator=(buffer&&) = default; + + + explicit + buffer(std::size_t capacity) + { + reserve(capacity); + } + + bool + empty() const + { + return size_ == 0; + } + + std::size_t + size() const + { + return size_; + } + + std::size_t + capacity() const + { + return capacity_; + } + + std::uint8_t const* + data() const + { + return p_.get(); + } + + std::uint8_t* + data() + { + return p_.get(); + } + + void + reserve(std::size_t capacity) + { + if(capacity != capacity_) + { + p_.reset(new std::uint8_t[capacity]); + capacity_ = capacity; + } + } + + void + resize(std::size_t size) + { + assert(size <= capacity_); + size_ = size; + } + }; + + buffer + make_source1(std::size_t size) + { + std::mt19937 rng; + buffer b(size); + auto p = b.data(); + std::size_t n = 0; + static std::string const chars( + "01234567890{}\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "{{{{{{{{{{}}}}}}}}}} "); + while(n < size) + { + *p++ = chars[rng()%chars.size()]; + ++n; + } + b.resize(n); + return b; + } + + buffer + make_source2(std::size_t size) + { + std::mt19937 rng; + std::array const i{0, 65535}; + std::array const w{0, 1}; + std::piecewise_linear_distribution d( + i.begin(), i.end(), w.begin()); + buffer b(size); + auto p = b.data(); + std::size_t n = 0; + while(n < size) + { + if(n == 1) + { + *p++ = rng()%256; + ++n; + continue; + } + auto const v = static_cast(d(rng)); + *p++ = v>>8; + *p++ = v&0xff; + n += 2; + + } + b.resize(n); + return b; + } + + void + checkInflate(buffer const& input, buffer const& original) + { + for(std::size_t i = 0; i < input.size(); ++i) + { + buffer output(original.size()); + inflate_stream zs; + zs.avail_in = 0; + zs.next_in = 0; + zs.next_out = output.data(); + zs.avail_out = output.capacity(); + if(i > 0) + { + zs.next_in = (Byte*)input.data(); + zs.avail_in = i; + auto result = zs.write(Z_FULL_FLUSH); + expect(result == Z_OK); + } + zs.next_in = (Byte*)input.data() + i; + zs.avail_in = input.size() - i; + auto result = zs.write(Z_FULL_FLUSH); + output.resize(output.capacity() - zs.avail_out); + expect(result == Z_OK); + expect(output.size() == original.size()); + expect(std::memcmp( + output.data(), original.data(), original.size()) == 0); + } + } + + void testSpecial() + { + { + deflate_stream zs; + } + { + inflate_stream zs; + } + } + + void testCompress() + { + static std::size_t constexpr N = 2048; + for(int source = 0; source <= 1; ++source) + { + buffer original; + switch(source) + { + case 0: + original = make_source1(N); + break; + case 1: + original = make_source2(N); + break; + } + for(int level = 0; level <= 9; ++level) + { + for(int strategy = 0; strategy <= 4; ++strategy) + { + for(int wbits = 15; wbits <= 15; ++wbits) + { + deflate_stream zs; + zs.avail_in = 0; + zs.next_in = 0; + expect(deflate_stream::deflateInit2(&zs, + level, + wbits, + 4, + strategy) == Z_OK); + buffer output(deflate_stream::deflateBound(&zs, original.size())); + zs.next_in = (Byte*)original.data(); + zs.avail_in = original.size(); + zs.next_out = output.data(); + zs.avail_out = output.capacity(); + auto result = zs.deflate(Z_FULL_FLUSH); + expect(result == Z_OK); + output.resize(output.capacity() - zs.avail_out); + checkInflate(output, original); + } + } + } + } + } + + void run() override + { + testSpecial(); + testCompress(); + } +}; + +BEAST_DEFINE_TESTSUITE(zlib,core,beast); + +} // zlib +} // beast + diff --git a/test/http/CMakeLists.txt b/test/http/CMakeLists.txt index af038f6db..a01c92cb6 100644 --- a/test/http/CMakeLists.txt +++ b/test/http/CMakeLists.txt @@ -11,14 +11,14 @@ add_executable (http-tests fail_parser.hpp ../../extras/beast/unit_test/main.cpp basic_dynabuf_body.cpp - basic_headers.cpp + basic_fields.cpp basic_parser_v1.cpp - body_type.cpp concepts.cpp empty_body.cpp - headers.cpp + fields.cpp + header_parser_v1.cpp message.cpp - message_v1.cpp + parse.cpp parse_error.cpp parser_v1.cpp read.cpp diff --git a/test/http/basic_headers.cpp b/test/http/basic_fields.cpp similarity index 82% rename from test/http/basic_headers.cpp rename to test/http/basic_fields.cpp index cc01d7d38..622d2f789 100644 --- a/test/http/basic_headers.cpp +++ b/test/http/basic_fields.cpp @@ -6,28 +6,29 @@ // // Test that header file is self-contained. -#include +#include #include +#include namespace beast { namespace http { -class basic_headers_test : public beast::unit_test::suite +class basic_fields_test : public beast::unit_test::suite { public: template - using bha = basic_headers; + using bha = basic_fields; - using bh = basic_headers>; + using bh = basic_fields>; template static void - fill(std::size_t n, basic_headers& h) + fill(std::size_t n, basic_fields& h) { for(std::size_t i = 1; i<= n; ++i) - h.insert(std::to_string(i), i); + h.insert(boost::lexical_cast(i), i); } template @@ -89,7 +90,7 @@ public: } }; -BEAST_DEFINE_TESTSUITE(basic_headers,http,beast); +BEAST_DEFINE_TESTSUITE(basic_fields,http,beast); } // http } // beast diff --git a/test/http/basic_parser_v1.cpp b/test/http/basic_parser_v1.cpp index 304be84f0..5cbe1c19b 100644 --- a/test/http/basic_parser_v1.cpp +++ b/test/http/basic_parser_v1.cpp @@ -14,8 +14,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -51,7 +51,8 @@ public: bool start = false; bool field = false; bool value = false; - bool headers = false; + bool fields = false; + bool _body_what = false; bool body = false; bool complete = false; @@ -90,10 +91,16 @@ public: { value = true; } - int on_headers(std::uint64_t, error_code&) + void + on_header(std::uint64_t, error_code&) { - headers = true; - return 0; + fields = true; + } + body_what + on_body_what(std::uint64_t, error_code&) + { + _body_what = true; + return body_what::normal; } void on_body(boost::string_ref const&, error_code&) { @@ -128,7 +135,8 @@ public: BEAST_EXPECT(p.request); BEAST_EXPECT(p.field); BEAST_EXPECT(p.value); - BEAST_EXPECT(p.headers); + BEAST_EXPECT(p.fields); + BEAST_EXPECT(p._body_what); BEAST_EXPECT(p.body); BEAST_EXPECT(p.complete); } @@ -150,7 +158,7 @@ public: BEAST_EXPECT(p.response); BEAST_EXPECT(p.field); BEAST_EXPECT(p.value); - BEAST_EXPECT(p.headers); + BEAST_EXPECT(p.fields); BEAST_EXPECT(p.body); BEAST_EXPECT(p.complete); } @@ -194,7 +202,7 @@ public: template void - good(int onBodyRv, std::string const& s, F const& f) + good(body_what onBodyRv, std::string const& s, F const& f) { using boost::asio::buffer; for_split(s, @@ -209,19 +217,19 @@ public: p.on_body_rv(onBodyRv); error_code ec; p.write(buffer(s1.data(), s1.size()), ec); - if(ec == test::fail_error) + if(ec == test::error::fail_error) continue; if(! BEAST_EXPECT(! ec)) break; if(! BEAST_EXPECT(s2.empty() || ! p.complete())) break; p.write(buffer(s2.data(), s2.size()), ec); - if(ec == test::fail_error) + if(ec == test::error::fail_error) continue; if(! BEAST_EXPECT(! ec)) break; p.write_eof(ec); - if(ec == test::fail_error) + if(ec == test::error::fail_error) continue; if(! BEAST_EXPECT(! ec)) break; @@ -237,12 +245,12 @@ public: void good(std::string const& s, F const& f = {}) { - return good(0, s, f); + return good(body_what::normal, s, f); } template void - bad(int onBodyRv, std::string const& s, error_code ev) + bad(body_what onBodyRv, std::string const& s, error_code ev) { using boost::asio::buffer; for_split(s, @@ -257,7 +265,7 @@ public: p.on_body_rv(onBodyRv); error_code ec; p.write(buffer(s1.data(), s1.size()), ec); - if(ec == test::fail_error) + if(ec == test::error::fail_error) continue; if(ec) { @@ -269,7 +277,7 @@ public: if(! s2.empty()) { p.write(buffer(s2.data(), s2.size()), ec); - if(ec == test::fail_error) + if(ec == test::error::fail_error) continue; if(ec) { @@ -280,7 +288,7 @@ public: break; } p.write_eof(ec); - if(ec == test::fail_error) + if(ec == test::error::fail_error) continue; BEAST_EXPECT(! p.complete()); BEAST_EXPECT((ec && ! ev) || ec == ev); @@ -294,7 +302,7 @@ public: void bad(std::string const& s, error_code ev = {}) { - return bad(0, s, ev); + return bad(body_what::normal, s, ev); } //-------------------------------------------------------------------------- @@ -658,7 +666,7 @@ public: auto const length = [&](std::string const& s, std::uint64_t v) { - good(1, s, + good(body_what::skip, s, [&](fail_parser const& p) { BEAST_EXPECT(p.content_length() == v); @@ -757,7 +765,7 @@ public: good(m("Transfer-Encodings: 2\r\n"), flags{*this, 0}); good(m("Transfer-Encoded: false\r\n"), flags{*this, 0}); - bad(1, + bad(body_what::skip, "HTTP/1.1 200 OK\r\n" "Content-Length: 1\r\n" "Transfer-Encoding: chunked\r\n" @@ -848,8 +856,8 @@ public: { error_code ec; test::fail_counter fc(1000); - fail_parser p(fc); - p.on_body_rv(2); + fail_parser p{fc}; + p.on_body_rv(body_what::upgrade); p.write(buf( "GET / HTTP/1.1\r\n" "Content-Length: 1\r\n" @@ -1007,12 +1015,7 @@ public: BEAST_EXPECT(p.complete()); } - bad(3, - "HTTP/1.1 200 OK\r\n" - "Content-Length: 1\r\n" - "\r\n*", parse_error::bad_on_headers_rv); - - bad(0, + bad(body_what::normal, "GET / HTTP/1.1\r\n" "Content-Length: 1\r\n" "\r\n", @@ -1101,7 +1104,7 @@ public: { test::fail_counter fc(1000); fail_parser p(fc); - p.set_option(headers_max_size{n}); + p.set_option(header_max_size{n}); error_code ec; p.write(buf( "GET / HTTP/1.1\r\n" @@ -1110,7 +1113,7 @@ public: ), ec); if(! ec) break; - BEAST_EXPECT(ec == parse_error::headers_too_big); + BEAST_EXPECT(ec == parse_error::header_too_big); } BEAST_EXPECT(n < Limit); } @@ -1119,7 +1122,7 @@ public: { test::fail_counter fc(1000); fail_parser p(fc); - p.set_option(headers_max_size{n}); + p.set_option(header_max_size{n}); error_code ec; p.write(buf( "HTTP/1.1 200 OK\r\n" @@ -1130,7 +1133,7 @@ public: ), ec); if(! ec) break; - BEAST_EXPECT(ec == parse_error::headers_too_big); + BEAST_EXPECT(ec == parse_error::header_too_big); } BEAST_EXPECT(n < Limit); } diff --git a/test/http/chunk_encode.cpp b/test/http/chunk_encode.cpp index f44e3eca9..cff31cbda 100644 --- a/test/http/chunk_encode.cpp +++ b/test/http/chunk_encode.cpp @@ -5,13 +5,14 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // -#include +// Test that header file is self-contained. +#include + #include #include namespace beast { namespace http { -namespace detail { class chunk_encode_test : public beast::unit_test::suite { @@ -35,8 +36,8 @@ public: { using boost::asio::buffer; if(! fc.s.empty()) - s.append(to_string( - chunk_encode(buffer(fc.s.data(), fc.s.size())))); + s.append(to_string(chunk_encode( + false, buffer(fc.s.data(), fc.s.size())))); s.append(to_string(chunk_encode_final())); } @@ -45,8 +46,8 @@ public: encode1(std::string& s, std::string const& piece) { using boost::asio::buffer; - s.append(to_string( - chunk_encode(buffer(piece.data(), piece.size())))); + s.append(to_string(chunk_encode( + false, buffer(piece.data(), piece.size())))); } static @@ -122,11 +123,14 @@ public: "****\r\n" "0\r\n\r\n", "****", final_chunk{}); + + BEAST_EXPECT(to_string(chunk_encode(true, + boost::asio::buffer("****", 4))) == + "4\r\n****\r\n0\r\n\r\n"); } }; BEAST_DEFINE_TESTSUITE(chunk_encode,http,beast); -} // detail } // http } // beast diff --git a/test/http/fail_parser.hpp b/test/http/fail_parser.hpp index 003992a29..3cb049600 100644 --- a/test/http/fail_parser.hpp +++ b/test/http/fail_parser.hpp @@ -20,7 +20,7 @@ class fail_parser { test::fail_counter& fc_; std::uint64_t content_length_ = no_content_length; - int body_rv_ = 0; + body_what body_rv_ = body_what::normal; public: std::string body; @@ -33,7 +33,7 @@ public: } void - on_body_rv(int rv) + on_body_rv(body_what rv) { body_rv_ = rv; } @@ -85,10 +85,18 @@ public: fc_.fail(ec); } - int on_headers(std::uint64_t content_length, error_code& ec) + void + on_header(std::uint64_t content_length, error_code& ec) { if(fc_.fail(ec)) - return 0; + return; + } + + body_what + on_body_what(std::uint64_t content_length, error_code& ec) + { + if(fc_.fail(ec)) + return body_what::normal; content_length_ = content_length; return body_rv_; } diff --git a/test/http/headers.cpp b/test/http/fields.cpp similarity index 89% rename from test/http/headers.cpp rename to test/http/fields.cpp index 79d68ffb6..4a0f5fa81 100644 --- a/test/http/headers.cpp +++ b/test/http/fields.cpp @@ -6,4 +6,4 @@ // // Test that header file is self-contained. -#include +#include diff --git a/test/http/header_parser_v1.cpp b/test/http/header_parser_v1.cpp new file mode 100644 index 000000000..61a35c2be --- /dev/null +++ b/test/http/header_parser_v1.cpp @@ -0,0 +1,90 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Test that header file is self-contained. +#include + +#include +#include +#include + +namespace beast { +namespace http { + +class header_parser_v1_test : public beast::unit_test::suite +{ +public: + void testParser() + { + { + error_code ec; + header_parser_v1 p; + BEAST_EXPECT(! p.complete()); + auto const n = p.write(boost::asio::buffer( + "GET / HTTP/1.1\r\n" + "User-Agent: test\r\n" + "\r\n" + ), ec); + BEAST_EXPECTS(! ec, ec.message()); + BEAST_EXPECT(p.complete()); + BEAST_EXPECT(n == 36); + } + { + error_code ec; + header_parser_v1 p; + BEAST_EXPECT(! p.complete()); + auto const n = p.write(boost::asio::buffer( + "GET / HTTP/1.1\r\n" + "User-Agent: test\r\n" + "Content-Length: 5\r\n" + "\r\n" + "*****" + ), ec); + BEAST_EXPECT(n == 55); + BEAST_EXPECTS(! ec, ec.message()); + BEAST_EXPECT(p.complete()); + } + { + error_code ec; + header_parser_v1 p; + BEAST_EXPECT(! p.complete()); + auto const n = p.write(boost::asio::buffer( + "HTTP/1.1 200 OK\r\n" + "Server: test\r\n" + "\r\n" + ), ec); + BEAST_EXPECT(n == 33); + BEAST_EXPECTS(! ec, ec.message()); + BEAST_EXPECT(p.complete()); + } + { + error_code ec; + header_parser_v1 p; + BEAST_EXPECT(! p.complete()); + auto const n = p.write(boost::asio::buffer( + "HTTP/1.1 200 OK\r\n" + "Server: test\r\n" + "Content-Length: 5\r\n" + "\r\n" + "*****" + ), ec); + BEAST_EXPECT(n == 52); + BEAST_EXPECTS(! ec, ec.message()); + BEAST_EXPECT(p.complete()); + } + } + + void run() override + { + testParser(); + } +}; + +BEAST_DEFINE_TESTSUITE(header_parser_v1,http,beast); + +} // http +} // beast diff --git a/test/http/message.cpp b/test/http/message.cpp index 68696a06c..d5db86e08 100644 --- a/test/http/message.cpp +++ b/test/http/message.cpp @@ -8,7 +8,8 @@ // Test that header file is self-contained. #include -#include +#include +#include #include #include #include @@ -69,71 +70,69 @@ public: }; }; - void testConstruction() + void testMessage() { static_assert(std::is_constructible< - message>::value, ""); + message>::value, ""); static_assert(std::is_constructible< - message, Arg1>::value, ""); + message, Arg1>::value, ""); static_assert(std::is_constructible< - message, Arg1 const>::value, ""); + message, Arg1 const>::value, ""); static_assert(std::is_constructible< - message, Arg1 const&>::value, ""); + message, Arg1 const&>::value, ""); static_assert(std::is_constructible< - message, Arg1&&>::value, ""); + message, Arg1&&>::value, ""); static_assert(! std::is_constructible< - message>::value, ""); + message>::value, ""); static_assert(std::is_constructible< - message, - Arg1, headers::allocator_type>::value, ""); + message, + Arg1, fields::allocator_type>::value, ""); static_assert(std::is_constructible< - message, std::piecewise_construct_t, + message, std::piecewise_construct_t, std::tuple>::value, ""); static_assert(std::is_constructible< - message, std::piecewise_construct_t, + message, std::piecewise_construct_t, std::tuple>::value, ""); static_assert(std::is_constructible< - message, std::piecewise_construct_t, - std::tuple, std::tuple>::value, ""); + message, std::piecewise_construct_t, + std::tuple, std::tuple>::value, ""); { Arg1 arg1; - message{std::move(arg1)}; + message{std::move(arg1)}; BEAST_EXPECT(arg1.moved); } { - headers h; + fields h; h.insert("User-Agent", "test"); - message m{Arg1{}, h}; + message m{Arg1{}, h}; BEAST_EXPECT(h["User-Agent"] == "test"); - BEAST_EXPECT(m.headers["User-Agent"] == "test"); + BEAST_EXPECT(m.fields["User-Agent"] == "test"); } { - headers h; + fields h; h.insert("User-Agent", "test"); - message m{Arg1{}, std::move(h)}; + message m{Arg1{}, std::move(h)}; BEAST_EXPECT(! h.exists("User-Agent")); - BEAST_EXPECT(m.headers["User-Agent"] == "test"); + BEAST_EXPECT(m.fields["User-Agent"] == "test"); } - } - void testSwap() - { - message m1; - message m2; + // swap + message m1; + message m2; m1.url = "u"; m1.body = "1"; - m1.headers.insert("h", "v"); + m1.fields.insert("h", "v"); m2.method = "G"; m2.body = "2"; swap(m1, m2); @@ -143,13 +142,148 @@ public: BEAST_EXPECT(m2.url == "u"); BEAST_EXPECT(m1.body == "2"); BEAST_EXPECT(m2.body == "1"); - BEAST_EXPECT(! m1.headers.exists("h")); - BEAST_EXPECT(m2.headers.exists("h")); + BEAST_EXPECT(! m1.fields.exists("h")); + BEAST_EXPECT(m2.fields.exists("h")); + } + + struct MoveHeaders + { + bool moved_to = false; + bool moved_from = false; + + MoveHeaders() = default; + + MoveHeaders(MoveHeaders&& other) + : moved_to(true) + { + other.moved_from = true; + } + + MoveHeaders& operator=(MoveHeaders&& other) + { + return *this; + } + }; + + void testHeaders() + { + { + using req_type = request_header; + static_assert(std::is_copy_constructible::value, ""); + static_assert(std::is_move_constructible::value, ""); + static_assert(std::is_copy_assignable::value, ""); + static_assert(std::is_move_assignable::value, ""); + + using res_type = response_header; + static_assert(std::is_copy_constructible::value, ""); + static_assert(std::is_move_constructible::value, ""); + static_assert(std::is_copy_assignable::value, ""); + static_assert(std::is_move_assignable::value, ""); + } + + { + MoveHeaders h; + header r{std::move(h)}; + BEAST_EXPECT(h.moved_from); + BEAST_EXPECT(r.fields.moved_to); + request m{std::move(r)}; + BEAST_EXPECT(r.fields.moved_from); + BEAST_EXPECT(m.fields.moved_to); + } + } + + void testFreeFunctions() + { + { + request m; + m.method = "GET"; + m.url = "/"; + m.version = 11; + m.fields.insert("Upgrade", "test"); + BEAST_EXPECT(! is_upgrade(m)); + + prepare(m, connection::upgrade); + BEAST_EXPECT(is_upgrade(m)); + BEAST_EXPECT(m.fields["Connection"] == "upgrade"); + + m.version = 10; + BEAST_EXPECT(! is_upgrade(m)); + } + } + + void testPrepare() + { + request m; + m.version = 10; + BEAST_EXPECT(! is_upgrade(m)); + m.fields.insert("Transfer-Encoding", "chunked"); + try + { + prepare(m); + fail(); + } + catch(std::exception const&) + { + } + m.fields.erase("Transfer-Encoding"); + m.fields.insert("Content-Length", "0"); + try + { + prepare(m); + fail(); + } + catch(std::exception const&) + { + pass(); + } + m.fields.erase("Content-Length"); + m.fields.insert("Connection", "keep-alive"); + try + { + prepare(m); + fail(); + } + catch(std::exception const&) + { + pass(); + } + m.version = 11; + m.fields.erase("Connection"); + m.fields.insert("Connection", "close"); + BEAST_EXPECT(! is_keep_alive(m)); + } + + void testSwap() + { + message m1; + message m2; + m1.status = 200; + m1.version = 10; + m1.body = "1"; + m1.fields.insert("h", "v"); + m2.status = 404; + m2.reason = "OK"; + m2.body = "2"; + m2.version = 11; + swap(m1, m2); + BEAST_EXPECT(m1.status == 404); + BEAST_EXPECT(m2.status == 200); + BEAST_EXPECT(m1.reason == "OK"); + BEAST_EXPECT(m2.reason.empty()); + BEAST_EXPECT(m1.version == 11); + BEAST_EXPECT(m2.version == 10); + BEAST_EXPECT(m1.body == "2"); + BEAST_EXPECT(m2.body == "1"); + BEAST_EXPECT(! m1.fields.exists("h")); + BEAST_EXPECT(m2.fields.exists("h")); } void run() override { - testConstruction(); + testMessage(); + testHeaders(); + testFreeFunctions(); + testPrepare(); testSwap(); } }; @@ -158,4 +292,3 @@ BEAST_DEFINE_TESTSUITE(message,http,beast); } // http } // beast - diff --git a/test/http/message_fuzz.hpp b/test/http/message_fuzz.hpp index e736c9607..d76ebedcf 100644 --- a/test/http/message_fuzz.hpp +++ b/test/http/message_fuzz.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -474,7 +475,7 @@ public: template void - headers(DynamicBuffer& db) + fields(DynamicBuffer& db) { while(rand(6)) { @@ -513,7 +514,7 @@ public: write(db, "Transfer-Encoding: chunked\r\n\r\n"); while(len > 0) { - auto n = std::min(1 + rand(300), len); + auto n = (std::min)(1 + rand(300), len); len -= n; write(db, to_hex(n), "\r\n"); for(auto const& b : db.prepare(n)) @@ -535,7 +536,7 @@ public: request(DynamicBuffer& db) { write(db, method(), " ", uri(), " HTTP/1.1\r\n"); - headers(db); + fields(db); body(db); } @@ -548,7 +549,7 @@ public: write(db, " ", 100 + rand(401), " "); write(db, token()); write(db, "\r\n"); - headers(db); + fields(db); body(db); write(db, "\r\n"); } diff --git a/test/http/message_v1.cpp b/test/http/message_v1.cpp deleted file mode 100644 index faedd4237..000000000 --- a/test/http/message_v1.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// -// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -// - -// Test that header file is self-contained. -#include - -#include -#include -#include -#include - -namespace beast { -namespace http { - -class message_v1_test : public beast::unit_test::suite -{ -public: - void testFreeFunctions() - { - { - request_v1 m; - m.method = "GET"; - m.url = "/"; - m.version = 11; - m.headers.insert("Upgrade", "test"); - BEAST_EXPECT(! is_upgrade(m)); - - prepare(m, connection::upgrade); - BEAST_EXPECT(is_upgrade(m)); - BEAST_EXPECT(m.headers["Connection"] == "upgrade"); - - m.version = 10; - BEAST_EXPECT(! is_upgrade(m)); - } - } - - void testPrepare() - { - request_v1 m; - m.version = 10; - BEAST_EXPECT(! is_upgrade(m)); - m.headers.insert("Transfer-Encoding", "chunked"); - try - { - prepare(m); - fail(); - } - catch(std::exception const&) - { - } - m.headers.erase("Transfer-Encoding"); - m.headers.insert("Content-Length", "0"); - try - { - prepare(m); - fail(); - } - catch(std::exception const&) - { - pass(); - } - m.headers.erase("Content-Length"); - m.headers.insert("Connection", "keep-alive"); - try - { - prepare(m); - fail(); - } - catch(std::exception const&) - { - pass(); - } - m.version = 11; - m.headers.erase("Connection"); - m.headers.insert("Connection", "close"); - BEAST_EXPECT(! is_keep_alive(m)); - } - - void testSwap() - { - message_v1 m1; - message_v1 m2; - m1.status = 200; - m1.version = 10; - m1.body = "1"; - m1.headers.insert("h", "v"); - m2.status = 404; - m2.reason = "OK"; - m2.body = "2"; - m2.version = 11; - swap(m1, m2); - BEAST_EXPECT(m1.status == 404); - BEAST_EXPECT(m2.status == 200); - BEAST_EXPECT(m1.reason == "OK"); - BEAST_EXPECT(m2.reason.empty()); - BEAST_EXPECT(m1.version == 11); - BEAST_EXPECT(m2.version == 10); - BEAST_EXPECT(m1.body == "2"); - BEAST_EXPECT(m2.body == "1"); - BEAST_EXPECT(! m1.headers.exists("h")); - BEAST_EXPECT(m2.headers.exists("h")); - } - - void run() override - { - testFreeFunctions(); - testPrepare(); - testSwap(); - } -}; - -BEAST_DEFINE_TESTSUITE(message_v1,http,beast); - -} // http -} // beast diff --git a/test/http/nodejs_parser.hpp b/test/http/nodejs_parser.hpp index 19c09cd5d..a9611e557 100644 --- a/test/http/nodejs_parser.hpp +++ b/test/http/nodejs_parser.hpp @@ -10,7 +10,7 @@ #include "nodejs-parser/http_parser.h" -#include +#include #include #include #include @@ -174,7 +174,7 @@ public: error_code ec; auto const used = write(data, size, ec); if(ec) - throw boost::system::system_error{ec}; + throw system_error{ec}; return used; } @@ -189,7 +189,7 @@ public: error_code ec; auto const used = write(buffers, ec); if(ec) - throw boost::system::system_error{ec}; + throw system_error{ec}; return used; } @@ -204,7 +204,7 @@ public: error_code ec; write_eof(ec); if(ec) - throw boost::system::system_error{ec}; + throw system_error{ec}; } void @@ -736,12 +736,12 @@ nodejs_basic_parser::cb_chunk_complete(http_parser*) The parser may only be used once. */ -template +template class nodejs_parser - : public nodejs_basic_parser> + : public nodejs_basic_parser> { using message_type = - message_v1; + message; message_type m_; typename message_type::body_type::reader r_; @@ -781,7 +781,7 @@ private: void on_field(std::string const& field, std::string const& value) { - m_.headers.insert(field, value); + m_.fields.insert(field, value); } void @@ -795,7 +795,7 @@ private: bool on_request(unsigned method, std::string const& url, - int major, int minor, bool keep_alive, bool upgrade, + int major, int minor, bool /*keep_alive*/, bool /*upgrade*/, std::true_type) { m_.method = detail::method_to_string(method); @@ -818,7 +818,8 @@ private: { return on_request(method, url, major, minor, keep_alive, upgrade, - typename message_type::is_request{}); + std::integral_constant< + bool, message_type::is_request>{}); } bool @@ -826,6 +827,7 @@ private: int major, int minor, bool keep_alive, bool upgrade, std::true_type) { + beast::detail::ignore_unused(keep_alive, upgrade); m_.status = status; m_.reason = reason; m_.version = major * 10 + minor; @@ -846,7 +848,7 @@ private: { return on_response( status, reason, major, minor, keep_alive, upgrade, - std::integral_constant{}); + std::integral_constant{}); } void diff --git a/test/http/body_type.cpp b/test/http/parse.cpp similarity index 88% rename from test/http/body_type.cpp rename to test/http/parse.cpp index cfddca655..5033f4528 100644 --- a/test/http/body_type.cpp +++ b/test/http/parse.cpp @@ -6,4 +6,4 @@ // // Test that header file is self-contained. -#include +#include diff --git a/test/http/parse_error.cpp b/test/http/parse_error.cpp index 769d09e67..626c8e504 100644 --- a/test/http/parse_error.cpp +++ b/test/http/parse_error.cpp @@ -23,11 +23,13 @@ public: BEAST_EXPECT(std::string{ec.category().name()} == name); BEAST_EXPECT(! ec.message().empty()); BEAST_EXPECT(std::addressof(ec.category()) == - std::addressof(get_parse_error_category())); - BEAST_EXPECT(get_parse_error_category().equivalent(static_cast(ev), - ec.category().default_error_condition(static_cast(ev)))); - BEAST_EXPECT(get_parse_error_category().equivalent( - ec, static_cast(ev))); + std::addressof(detail::get_parse_error_category())); + BEAST_EXPECT(detail::get_parse_error_category().equivalent( + static_cast::type>(ev), + ec.category().default_error_condition( + static_cast::type>(ev)))); + BEAST_EXPECT(detail::get_parse_error_category().equivalent( + ec, static_cast::type>(ev))); } void run() override @@ -37,17 +39,18 @@ public: check("http", parse_error::bad_uri); check("http", parse_error::bad_version); check("http", parse_error::bad_crlf); - check("http", parse_error::bad_request); check("http", parse_error::bad_status); check("http", parse_error::bad_reason); check("http", parse_error::bad_field); check("http", parse_error::bad_value); check("http", parse_error::bad_content_length); check("http", parse_error::illegal_content_length); - check("http", parse_error::bad_on_headers_rv); check("http", parse_error::invalid_chunk_size); + check("http", parse_error::invalid_ext_name); + check("http", parse_error::invalid_ext_val); + check("http", parse_error::header_too_big); + check("http", parse_error::body_too_big); check("http", parse_error::short_read); - check("http", parse_error::general); } }; diff --git a/test/http/parser_bench.cpp b/test/http/parser_bench.cpp index c1840069e..a51d4822d 100644 --- a/test/http/parser_bench.cpp +++ b/test/http/parser_bench.cpp @@ -122,20 +122,20 @@ public: [&] { testParser>( + true, streambuf_body, fields>>( Repeat, creq_); testParser>( + false, streambuf_body, fields>>( Repeat, cres_); }); timedTest(Trials, "http::basic_parser_v1", [&] { testParser>( + true, streambuf_body, fields>>( Repeat, creq_); testParser>( + false, streambuf_body, fields>>( Repeat, cres_); }); pass(); diff --git a/test/http/parser_v1.cpp b/test/http/parser_v1.cpp index a5d3427cc..d9e5259ea 100644 --- a/test/http/parser_v1.cpp +++ b/test/http/parser_v1.cpp @@ -8,23 +8,87 @@ // Test that header file is self-contained. #include -#include +#include +#include +#include +#include #include +#include +#include #include namespace beast { namespace http { -class parser_v1_test : public beast::unit_test::suite +class parser_v1_test + : public beast::unit_test::suite + , public test::enable_yield_to { public: + void testRegressions() + { + using boost::asio::buffer; + + // consecutive empty header values + { + error_code ec; + parser_v1 p; + std::string const s = + "GET / HTTP/1.1\r\n" + "X1:\r\n" + "X2:\r\n" + "X3:x\r\n" + "\r\n"; + p.write(buffer(s), ec); + if(! BEAST_EXPECTS(! ec, ec.message())) + return; + BEAST_EXPECT(p.complete()); + auto const msg = p.release(); + BEAST_EXPECT(msg.fields.exists("X1")); + BEAST_EXPECT(msg.fields["X1"] == ""); + BEAST_EXPECT(msg.fields.exists("X2")); + BEAST_EXPECT(msg.fields["X2"] == ""); + BEAST_EXPECT(msg.fields.exists("X3")); + BEAST_EXPECT(msg.fields["X3"] == "x"); + } + } + + void testWithBody() + { + test::string_stream ss{ios_, + "GET / HTTP/1.1\r\n" + "User-Agent: test\r\n" + "Content-Length: 1\r\n" + "\r\n" + "*"}; + streambuf rb; + header_parser_v1 p0; + parse(ss, rb, p0); + request_header const& reqh = p0.get(); + BEAST_EXPECT(reqh.method == "GET"); + BEAST_EXPECT(reqh.url == "/"); + BEAST_EXPECT(reqh.version == 11); + BEAST_EXPECT(reqh.fields["User-Agent"] == "test"); + BEAST_EXPECT(reqh.fields["Content-Length"] == "1"); + parser_v1 p = + with_body(p0); + BEAST_EXPECT(p.get().method == "GET"); + BEAST_EXPECT(p.get().url == "/"); + BEAST_EXPECT(p.get().version == 11); + BEAST_EXPECT(p.get().fields["User-Agent"] == "test"); + BEAST_EXPECT(p.get().fields["Content-Length"] == "1"); + parse(ss, rb, p); + request req = p.release(); + BEAST_EXPECT(req.body == "*"); + } + void run() override { using boost::asio::buffer; { error_code ec; parser_v1>> p; + basic_fields>> p; std::string const s = "GET / HTTP/1.1\r\n" "User-Agent: test\r\n" @@ -38,13 +102,13 @@ public: BEAST_EXPECT(m.method == "GET"); BEAST_EXPECT(m.url == "/"); BEAST_EXPECT(m.version == 11); - BEAST_EXPECT(m.headers["User-Agent"] == "test"); + BEAST_EXPECT(m.fields["User-Agent"] == "test"); BEAST_EXPECT(m.body == "*"); } { error_code ec; parser_v1>> p; + basic_fields>> p; std::string const s = "HTTP/1.1 200 OK\r\n" "Server: test\r\n" @@ -58,13 +122,13 @@ public: BEAST_EXPECT(m.status == 200); BEAST_EXPECT(m.reason == "OK"); BEAST_EXPECT(m.version == 11); - BEAST_EXPECT(m.headers["Server"] == "test"); + BEAST_EXPECT(m.fields["Server"] == "test"); BEAST_EXPECT(m.body == "*"); } // skip body { error_code ec; - parser_v1 p; + parser_v1 p; std::string const s = "HTTP/1.1 200 Connection Established\r\n" "Proxy-Agent: Zscaler/5.1\r\n" @@ -74,6 +138,9 @@ public: BEAST_EXPECT(! ec); BEAST_EXPECT(p.complete()); } + + testRegressions(); + testWithBody(); } }; diff --git a/test/http/read.cpp b/test/http/read.cpp index f3f1c3279..8775dc2f8 100644 --- a/test/http/read.cpp +++ b/test/http/read.cpp @@ -10,7 +10,7 @@ #include "fail_parser.hpp" -#include +#include #include #include #include @@ -26,8 +26,62 @@ class read_test , public test::enable_yield_to { public: + struct fail_body + { + class reader; + + class value_type + { + friend class reader; + + std::string s_; + test::fail_counter& fc_; + + public: + explicit + value_type(test::fail_counter& fc) + : fc_(fc) + { + } + + value_type& + operator=(std::string s) + { + s_ = std::move(s); + return *this; + } + }; + + class reader + { + value_type& body_; + + public: + template + explicit + reader(message& msg) noexcept + : body_(msg.body) + { + } + + void + init(error_code& ec) noexcept + { + body_.fc_.fail(ec); + } + + void + write(void const* data, + std::size_t size, error_code& ec) noexcept + { + if(body_.fc_.fail(ec)) + return; + } + }; + }; + template - void failMatrix(const char* s, yield_context do_yield) + void failMatrix(char const* s, yield_context do_yield) { using boost::asio::buffer; using boost::asio::buffer_copy; @@ -96,6 +150,20 @@ public: break; } BEAST_EXPECT(n < limit); + for(n = 0; n < limit; ++n) + { + streambuf sb; + sb.commit(buffer_copy( + sb.prepare(len), buffer(s, len))); + test::fail_counter fc{n}; + test::string_stream ss{ios_, s}; + parser_v1 p{fc}; + error_code ec; + parse(ss, sb, p, ec); + if(! ec) + break; + } + BEAST_EXPECT(n < limit); } void testThrow() @@ -104,7 +172,7 @@ public: { streambuf sb; test::string_stream ss(ios_, "GET / X"); - parser_v1 p; + parser_v1 p; parse(ss, sb, p); fail(); } @@ -176,21 +244,21 @@ public: failMatrix(res[i], do_yield); } - void testRead(yield_context do_yield) + void testReadHeaders(yield_context do_yield) { static std::size_t constexpr limit = 100; std::size_t n; for(n = 0; n < limit; ++n) { - test::fail_stream fs(n, ios_, + test::fail_stream fs{n, ios_, "GET / HTTP/1.1\r\n" "Host: localhost\r\n" "User-Agent: test\r\n" - "Content-Length: 0\r\n" + "Content-Length: 5\r\n" "\r\n" - ); - request_v1 m; + }; + request_header m; try { streambuf sb; @@ -212,7 +280,53 @@ public: "Content-Length: 0\r\n" "\r\n" ); - request_v1 m; + request_header m; + error_code ec; + streambuf sb; + async_read(fs, sb, m, do_yield[ec]); + if(! ec) + break; + } + BEAST_EXPECT(n < limit); + } + + void testRead(yield_context do_yield) + { + static std::size_t constexpr limit = 100; + std::size_t n; + + for(n = 0; n < limit; ++n) + { + test::fail_stream fs(n, ios_, + "GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "User-Agent: test\r\n" + "Content-Length: 0\r\n" + "\r\n" + ); + request m; + try + { + streambuf sb; + read(fs, sb, m); + break; + } + catch(std::exception const&) + { + } + } + BEAST_EXPECT(n < limit); + + for(n = 0; n < limit; ++n) + { + test::fail_stream fs(n, ios_, + "GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "User-Agent: test\r\n" + "Content-Length: 0\r\n" + "\r\n" + ); + request m; error_code ec; streambuf sb; read(fs, sb, m, ec); @@ -230,7 +344,7 @@ public: "Content-Length: 0\r\n" "\r\n" ); - request_v1 m; + request m; error_code ec; streambuf sb; async_read(fs, sb, m, do_yield[ec]); @@ -245,7 +359,7 @@ public: { streambuf sb; test::string_stream ss(ios_, ""); - parser_v1 p; + parser_v1 p; error_code ec; parse(ss, sb, p, ec); BEAST_EXPECT(ec == boost::asio::error::eof); @@ -253,7 +367,7 @@ public: { streambuf sb; test::string_stream ss(ios_, ""); - parser_v1 p; + parser_v1 p; error_code ec; async_parse(ss, sb, p, do_yield[ec]); BEAST_EXPECT(ec == boost::asio::error::eof); @@ -267,6 +381,9 @@ public: yield_to(std::bind(&read_test::testFailures, this, std::placeholders::_1)); + yield_to(std::bind(&read_test::testReadHeaders, + this, std::placeholders::_1)); + yield_to(std::bind(&read_test::testRead, this, std::placeholders::_1)); diff --git a/test/http/rfc7230.cpp b/test/http/rfc7230.cpp index 49b1c9525..a1a6e8aeb 100644 --- a/test/http/rfc7230.cpp +++ b/test/http/rfc7230.cpp @@ -43,8 +43,11 @@ public: { s.push_back(';'); s.append(str(p.first)); - s.push_back('='); - s.append(str(p.second)); + if(! p.second.empty()) + { + s.push_back('='); + s.append(str(p.second)); + } } return s; } @@ -73,18 +76,19 @@ public: BEAST_EXPECTS(got == good, fmt(got)); }; + ce(""); + ce(";x"); + ce(";xy"); + ce(";x;y"); + ce(""); cs(" ;\t i =\t 1 \t", ";i=1"); cq("\t; \t xyz=1 ; ijk=\"q\\\"t\"", ";xyz=1;ijk=q\"t"); + ce(";x;y"); // invalid strings cs(";", ""); cs(";,", ""); - cs(";xy", ""); - cs(";xy", ""); - cs(";xy ", ""); - cs(";xy,", ""); - cq(";x=,", ""); cq(";xy=\"", ""); cq(";xy=\"\x7f", ""); @@ -136,7 +140,6 @@ public: param-list = *( OWS ";" OWS param ) param = token OWS "=" OWS ( token / quoted-string ) */ - ce(""); cs(",", ""); cs(", ", ""); cs(",\t", ""); @@ -147,12 +150,16 @@ public: cs("\t , \t", ""); cs(",,", ""); cs(" , \t,, \t,", ""); + cs( "permessage-deflate; client_no_context_takeover; client_max_window_bits", + "permessage-deflate;client_no_context_takeover;client_max_window_bits"); ce("a"); ce("ab"); ce("a,b"); cs(" a ", "a"); cs("\t a, b\t , c\t", "a,b,c"); + ce("a;b"); + ce("a;b;c"); cs("a; \t i\t=\t \t1\t ", "a;i=1"); ce("a;i=1;j=2;k=3"); diff --git a/test/http/streambuf_body.cpp b/test/http/streambuf_body.cpp index eec841220..e2ed38116 100644 --- a/test/http/streambuf_body.cpp +++ b/test/http/streambuf_body.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include #include @@ -34,7 +34,7 @@ public: "\r\n" "xyz"; test::string_stream ss(ios_, s); - parser_v1 p; + parser_v1 p; streambuf sb; parse(ss, sb, p); BEAST_EXPECT(to_string(p.get().body.data()) == "xyz"); diff --git a/test/http/write.cpp b/test/http/write.cpp index f08c6b624..514086d3d 100644 --- a/test/http/write.cpp +++ b/test/http/write.cpp @@ -8,7 +8,7 @@ // Test that header file is self-contained. #include -#include +#include #include #include #include @@ -64,7 +64,7 @@ public: template std::size_t write_some( - ConstBufferSequence const& buffers, error_code& ec) + ConstBufferSequence const& buffers, error_code&) { auto const n = buffer_size(buffers); using boost::asio::buffer_size; @@ -104,21 +104,23 @@ public: public: template explicit - writer(message const& msg) + writer(message const& msg) noexcept : body_(msg.body) { } void - init(error_code& ec) + init(error_code& ec) noexcept { + beast::detail::ignore_unused(ec); } - template + template boost::tribool - operator()(resume_context&&, error_code&, Write&& write) + write(resume_context&&, error_code&, + WriteFunction&& wf) noexcept { - write(boost::asio::buffer(body_)); + wf(boost::asio::buffer(body_)); return true; } }; @@ -168,13 +170,13 @@ public: public: template explicit - writer(message const& msg) + writer(message const& msg) noexcept : body_(msg.body) { } void - init(error_code& ec) + init(error_code& ec) noexcept { body_.fc_.fail(ec); } @@ -197,9 +199,10 @@ public: } }; - template + template boost::tribool - operator()(resume_context&& rc, error_code& ec, Write&& write) + write(resume_context&& rc, error_code& ec, + WriteFunction&& wf) noexcept { if(body_.fc_.fail(ec)) return false; @@ -211,16 +214,16 @@ public: } if(n_ >= body_.s_.size()) return true; - write(boost::asio::buffer(body_.s_.data() + n_, 1)); + wf(boost::asio::buffer(body_.s_.data() + n_, 1)); ++n_; return n_ == body_.s_.size(); } }; }; - template + template std::string - str(message_v1 const& m) + str(message const& m) { string_write_stream ss(ios_); write(ss, m); @@ -228,18 +231,55 @@ public: } void - testAsyncWrite(yield_context do_yield) + testAsyncWriteHeaders(yield_context do_yield) { { - message_v1 m; + header m; + m.version = 11; + m.method = "GET"; + m.url = "/"; + m.fields.insert("User-Agent", "test"); + error_code ec; + string_write_stream ss{ios_}; + async_write(ss, m, do_yield[ec]); + if(BEAST_EXPECTS(! ec, ec.message())) + BEAST_EXPECT(ss.str == + "GET / HTTP/1.1\r\n" + "User-Agent: test\r\n" + "\r\n"); + } + { + header m; m.version = 10; m.status = 200; m.reason = "OK"; - m.headers.insert("Server", "test"); - m.headers.insert("Content-Length", "5"); + m.fields.insert("Server", "test"); + m.fields.insert("Content-Length", "5"); + error_code ec; + string_write_stream ss{ios_}; + async_write(ss, m, do_yield[ec]); + if(BEAST_EXPECTS(! ec, ec.message())) + BEAST_EXPECT(ss.str == + "HTTP/1.0 200 OK\r\n" + "Server: test\r\n" + "Content-Length: 5\r\n" + "\r\n"); + } + } + + void + testAsyncWrite(yield_context do_yield) + { + { + message m; + m.version = 10; + m.status = 200; + m.reason = "OK"; + m.fields.insert("Server", "test"); + m.fields.insert("Content-Length", "5"); m.body = "*****"; error_code ec; - string_write_stream ss(ios_); + string_write_stream ss{ios_}; async_write(ss, m, do_yield[ec]); if(BEAST_EXPECTS(! ec, ec.message())) BEAST_EXPECT(ss.str == @@ -250,12 +290,12 @@ public: "*****"); } { - message_v1 m; + message m; m.version = 11; m.status = 200; m.reason = "OK"; - m.headers.insert("Server", "test"); - m.headers.insert("Transfer-Encoding", "chunked"); + m.fields.insert("Server", "test"); + m.fields.insert("Transfer-Encoding", "chunked"); m.body = "*****"; error_code ec; string_write_stream ss(ios_); @@ -283,14 +323,14 @@ public: test::fail_counter fc(n); test::fail_stream< string_write_stream> fs(fc, ios_); - message_v1 m( + message m( std::piecewise_construct, std::forward_as_tuple(fc, ios_)); m.method = "GET"; m.url = "/"; m.version = 10; - m.headers.insert("User-Agent", "test"); - m.headers.insert("Content-Length", "5"); + m.fields.insert("User-Agent", "test"); + m.fields.insert("Content-Length", "5"); m.body = "*****"; try { @@ -316,14 +356,14 @@ public: test::fail_counter fc(n); test::fail_stream< string_write_stream> fs(fc, ios_); - message_v1 m( + message m( std::piecewise_construct, std::forward_as_tuple(fc, ios_)); m.method = "GET"; m.url = "/"; m.version = 10; - m.headers.insert("User-Agent", "test"); - m.headers.insert("Transfer-Encoding", "chunked"); + m.fields.insert("User-Agent", "test"); + m.fields.insert("Transfer-Encoding", "chunked"); m.body = "*****"; error_code ec; write(fs, m, ec); @@ -351,14 +391,14 @@ public: test::fail_counter fc(n); test::fail_stream< string_write_stream> fs(fc, ios_); - message_v1 m( + message m( std::piecewise_construct, std::forward_as_tuple(fc, ios_)); m.method = "GET"; m.url = "/"; m.version = 10; - m.headers.insert("User-Agent", "test"); - m.headers.insert("Transfer-Encoding", "chunked"); + m.fields.insert("User-Agent", "test"); + m.fields.insert("Transfer-Encoding", "chunked"); m.body = "*****"; error_code ec; async_write(fs, m, do_yield[ec]); @@ -386,14 +426,14 @@ public: test::fail_counter fc(n); test::fail_stream< string_write_stream> fs(fc, ios_); - message_v1 m( + message m( std::piecewise_construct, std::forward_as_tuple(fc, ios_)); m.method = "GET"; m.url = "/"; m.version = 10; - m.headers.insert("User-Agent", "test"); - m.headers.insert("Content-Length", "5"); + m.fields.insert("User-Agent", "test"); + m.fields.insert("Content-Length", "5"); m.body = "*****"; error_code ec; write(fs, m, ec); @@ -416,14 +456,14 @@ public: test::fail_counter fc(n); test::fail_stream< string_write_stream> fs(fc, ios_); - message_v1 m( + message m( std::piecewise_construct, std::forward_as_tuple(fc, ios_)); m.method = "GET"; m.url = "/"; m.version = 10; - m.headers.insert("User-Agent", "test"); - m.headers.insert("Content-Length", "5"); + m.fields.insert("User-Agent", "test"); + m.fields.insert("Content-Length", "5"); m.body = "*****"; error_code ec; async_write(fs, m, do_yield[ec]); @@ -447,11 +487,11 @@ public: { // auto content-length HTTP/1.0 { - message_v1 m; + message m; m.method = "GET"; m.url = "/"; m.version = 10; - m.headers.insert("User-Agent", "test"); + m.fields.insert("User-Agent", "test"); m.body = "*"; prepare(m); BEAST_EXPECT(str(m) == @@ -464,11 +504,11 @@ public: } // keep-alive HTTP/1.0 { - message_v1 m; + message m; m.method = "GET"; m.url = "/"; m.version = 10; - m.headers.insert("User-Agent", "test"); + m.fields.insert("User-Agent", "test"); m.body = "*"; prepare(m, connection::keep_alive); BEAST_EXPECT(str(m) == @@ -482,11 +522,11 @@ public: } // upgrade HTTP/1.0 { - message_v1 m; + message m; m.method = "GET"; m.url = "/"; m.version = 10; - m.headers.insert("User-Agent", "test"); + m.fields.insert("User-Agent", "test"); m.body = "*"; try { @@ -500,11 +540,11 @@ public: } // no content-length HTTP/1.0 { - message_v1 m; + message m; m.method = "GET"; m.url = "/"; m.version = 10; - m.headers.insert("User-Agent", "test"); + m.fields.insert("User-Agent", "test"); m.body = "*"; prepare(m); string_write_stream ss(ios_); @@ -520,11 +560,11 @@ public: } // auto content-length HTTP/1.1 { - message_v1 m; + message m; m.method = "GET"; m.url = "/"; m.version = 11; - m.headers.insert("User-Agent", "test"); + m.fields.insert("User-Agent", "test"); m.body = "*"; prepare(m); BEAST_EXPECT(str(m) == @@ -537,11 +577,11 @@ public: } // close HTTP/1.1 { - message_v1 m; + message m; m.method = "GET"; m.url = "/"; m.version = 11; - m.headers.insert("User-Agent", "test"); + m.fields.insert("User-Agent", "test"); m.body = "*"; prepare(m, connection::close); string_write_stream ss(ios_); @@ -559,11 +599,11 @@ public: } // upgrade HTTP/1.1 { - message_v1 m; + message m; m.method = "GET"; m.url = "/"; m.version = 11; - m.headers.insert("User-Agent", "test"); + m.fields.insert("User-Agent", "test"); prepare(m, connection::upgrade); BEAST_EXPECT(str(m) == "GET / HTTP/1.1\r\n" @@ -574,11 +614,11 @@ public: } // no content-length HTTP/1.1 { - message_v1 m; + message m; m.method = "GET"; m.url = "/"; m.version = 11; - m.headers.insert("User-Agent", "test"); + m.fields.insert("User-Agent", "test"); m.body = "*"; prepare(m); string_write_stream ss(ios_); @@ -596,26 +636,54 @@ public: } } - void testConvert() + void test_std_ostream() { - message_v1 m; + // Conversion to std::string via operator<< + message m; m.method = "GET"; m.url = "/"; m.version = 11; - m.headers.insert("User-Agent", "test"); + m.fields.insert("User-Agent", "test"); m.body = "*"; - prepare(m); BEAST_EXPECT(boost::lexical_cast(m) == - "GET / HTTP/1.1\r\nUser-Agent: test\r\nContent-Length: 1\r\n\r\n*"); + "GET / HTTP/1.1\r\nUser-Agent: test\r\n\r\n*"); + BEAST_EXPECT(boost::lexical_cast(m.base()) == + "GET / HTTP/1.1\r\nUser-Agent: test\r\n\r\n"); + // Cause exceptions in operator<< + { + std::stringstream ss; + ss.setstate(ss.rdstate() | + std::stringstream::failbit); + try + { + // header + ss << m.base(); + fail("", __FILE__, __LINE__); + } + catch(std::exception const&) + { + pass(); + } + try + { + // message + ss << m; + fail("", __FILE__, __LINE__); + } + catch(std::exception const&) + { + pass(); + } + } } void testOstream() { - message_v1 m; + message m; m.method = "GET"; m.url = "/"; m.version = 11; - m.headers.insert("User-Agent", "test"); + m.fields.insert("User-Agent", "test"); m.body = "*"; prepare(m); std::stringstream ss; @@ -634,12 +702,14 @@ public: void run() override { + yield_to(std::bind(&write_test::testAsyncWriteHeaders, + this, std::placeholders::_1)); yield_to(std::bind(&write_test::testAsyncWrite, this, std::placeholders::_1)); yield_to(std::bind(&write_test::testFailures, this, std::placeholders::_1)); testOutput(); - testConvert(); + test_std_ostream(); testOstream(); } }; diff --git a/test/websocket/CMakeLists.txt b/test/websocket/CMakeLists.txt index 5cc4c20b1..9de18db9f 100644 --- a/test/websocket/CMakeLists.txt +++ b/test/websocket/CMakeLists.txt @@ -17,7 +17,6 @@ add_executable (websocket-tests teardown.cpp frame.cpp mask.cpp - stream_base.cpp utf8_checker.cpp ) @@ -25,6 +24,10 @@ if (NOT WIN32) target_link_libraries(websocket-tests ${Boost_LIBRARIES} Threads::Threads) endif() +if (MINGW) + set_target_properties(websocket-tests PROPERTIES COMPILE_FLAGS "-Wa,-mbig-obj -Og") +endif() + add_executable (websocket-echo ${BEAST_INCLUDES} ${EXTRAS_INCLUDES} diff --git a/test/websocket/error.cpp b/test/websocket/error.cpp index 29a0210fa..a46b4c3a2 100644 --- a/test/websocket/error.cpp +++ b/test/websocket/error.cpp @@ -24,10 +24,12 @@ public: BEAST_EXPECT(! ec.message().empty()); BEAST_EXPECT(std::addressof(ec.category()) == std::addressof(detail::get_error_category())); - BEAST_EXPECT(detail::get_error_category().equivalent(static_cast(ev), - ec.category().default_error_condition(static_cast(ev)))); BEAST_EXPECT(detail::get_error_category().equivalent( - ec, static_cast(ev))); + static_cast::type>(ev), + ec.category().default_error_condition( + static_cast::type>(ev)))); + BEAST_EXPECT(detail::get_error_category().equivalent( + ec, static_cast::type>(ev))); } void run() override @@ -48,5 +50,5 @@ public: BEAST_DEFINE_TESTSUITE(error,websocket,beast); -} // http +} // websocket } // beast diff --git a/test/websocket/frame.cpp b/test/websocket/frame.cpp index 0be416a8a..522c72f8b 100644 --- a/test/websocket/frame.cpp +++ b/test/websocket/frame.cpp @@ -6,6 +6,7 @@ // #include +#include #include #include #include @@ -67,7 +68,7 @@ public: void testFrameHeader() { - // good frame headers + // good frame fields { role_type role = role_type::client; @@ -76,20 +77,20 @@ public: { fh_streambuf sb; write(sb, fh); - frame_header fh1; close_code::value code; - auto const n = read_fh1( - fh1, sb, role, code); + stream_base stream; + stream.open(role); + auto const n = stream.read_fh1(sb, code); if(! BEAST_EXPECT(! code)) return; if(! BEAST_EXPECT(sb.size() == n)) return; - read_fh2(fh1, sb, role, code); + stream.read_fh2(sb, code); if(! BEAST_EXPECT(! code)) return; if(! BEAST_EXPECT(sb.size() == 0)) return; - BEAST_EXPECT(fh1 == fh); + BEAST_EXPECT(stream.rd_fh_ == fh); }; test_fh fh; @@ -113,11 +114,11 @@ public: fh.len = 65536; check(fh); - fh.len = std::numeric_limits::max(); + fh.len = 65537; check(fh); } - // bad frame headers + // bad frame fields { role_type role = role_type::client; @@ -126,10 +127,10 @@ public: { fh_streambuf sb; write(sb, fh); - frame_header fh1; close_code::value code; - auto const n = read_fh1( - fh1, sb, role, code); + stream_base stream; + stream.open(role); + auto const n = stream.read_fh1(sb, code); if(code) { pass(); @@ -137,7 +138,7 @@ public: } if(! BEAST_EXPECT(sb.size() == n)) return; - read_fh2(fh1, sb, role, code); + stream.read_fh2(sb, code); if(! BEAST_EXPECT(code)) return; if(! BEAST_EXPECT(sb.size() == 0)) @@ -186,15 +187,14 @@ public: { using boost::asio::buffer; using boost::asio::buffer_copy; - static role_type constexpr role = - role_type::client; + static role_type constexpr role = role_type::client; std::vector v{bs}; fh_streambuf sb; - sb.commit(buffer_copy( - sb.prepare(v.size()), buffer(v))); - frame_header fh; + sb.commit(buffer_copy(sb.prepare(v.size()), buffer(v))); + stream_base stream; + stream.open(role); close_code::value code; - auto const n = read_fh1(fh, sb, role, code); + auto const n = stream.read_fh1(sb, code); if(code) { pass(); @@ -202,7 +202,7 @@ public: } if(! BEAST_EXPECT(sb.size() == n)) return; - read_fh2(fh, sb, role, code); + stream.read_fh2(sb, code); if(! BEAST_EXPECT(code)) return; if(! BEAST_EXPECT(sb.size() == 0)) @@ -211,7 +211,7 @@ public: void testBadFrameHeaders() { - // bad frame headers + // bad frame fields // // can't be created by the library // so we produce them manually. @@ -233,4 +233,3 @@ BEAST_DEFINE_TESTSUITE(frame,websocket,beast); } // detail } // websocket } // beast - diff --git a/test/websocket/stream.cpp b/test/websocket/stream.cpp index 775c3c06a..084019ebe 100644 --- a/test/websocket/stream.cpp +++ b/test/websocket/stream.cpp @@ -133,15 +133,15 @@ public: struct identity { - template + template void - operator()(http::message&) + operator()(http::message&) { } - template + template void - operator()(http::message&) + operator()(http::message&) { } }; @@ -149,16 +149,16 @@ public: void testOptions() { stream ws(ios_); - ws.set_option(auto_fragment_size{2048}); + ws.set_option(auto_fragment{true}); ws.set_option(decorate(identity{})); ws.set_option(keep_alive{false}); - ws.set_option(mask_buffer_size(2048)); + ws.set_option(write_buffer_size{2048}); ws.set_option(message_type{opcode::text}); - ws.set_option(read_buffer_size(8192)); - ws.set_option(read_message_max(1 * 1024 * 1024)); + ws.set_option(read_buffer_size{8192}); + ws.set_option(read_message_max{1 * 1024 * 1024}); try { - ws.set_option(mask_buffer_size(0)); + ws.set_option(write_buffer_size{7}); fail(); } catch(std::exception const&) @@ -184,15 +184,15 @@ public: for(n = 0; n < limit; ++n) { // valid - http::request_v1 req; + http::request req; req.method = "GET"; req.url = "/"; req.version = 11; - req.headers.insert("Host", "localhost"); - req.headers.insert("Upgrade", "websocket"); - req.headers.insert("Connection", "upgrade"); - req.headers.insert("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ=="); - req.headers.insert("Sec-WebSocket-Version", "13"); + req.fields.insert("Host", "localhost"); + req.fields.insert("Upgrade", "websocket"); + req.fields.insert("Connection", "upgrade"); + req.fields.insert("Sec-WebSocket-Key", "dGhlIHNhbXBsZSBub25jZQ=="); + req.fields.insert("Sec-WebSocket-Version", "13"); stream> ws(n, ios_, ""); try @@ -263,7 +263,7 @@ public: } catch(system_error const& se) { - BEAST_EXPECT(se.code() == ev); + BEAST_EXPECTS(se.code() == ev, se.what()); } } }; @@ -490,7 +490,7 @@ public: } } - void testClose(endpoint_type const& ep, yield_context do_yield) + void testClose(endpoint_type const& ep, yield_context) { { // payload length 1 @@ -816,7 +816,7 @@ public: fail(); return false; } - catch(boost::system::system_error const& se) + catch(system_error const& se) { if(se.code() != ev) throw; @@ -840,7 +840,7 @@ public: ws.handshake("localhost", "/"); // send message - ws.set_option(auto_fragment_size(0)); + ws.set_option(auto_fragment{false}); ws.set_option(message_type(opcode::text)); ws.write(sbuf("Hello")); { @@ -910,22 +910,27 @@ public: } ws.set_option(pong_callback{}); + // send pong + ws.pong(""); + // send auto fragmented message - ws.set_option(auto_fragment_size(3)); - ws.write(sbuf("Hello")); + ws.set_option(auto_fragment{true}); + ws.set_option(write_buffer_size{8}); + ws.write(sbuf("Now is the time for all good men")); { // receive echoed message opcode op; - streambuf db; - ws.read(op, db); - BEAST_EXPECT(to_string(db.data()) == "Hello"); + streambuf sb; + ws.read(op, sb); + BEAST_EXPECT(to_string(sb.data()) == "Now is the time for all good men"); } - ws.set_option(auto_fragment_size(0)); + ws.set_option(auto_fragment{false}); + ws.set_option(write_buffer_size{4096}); // send message with write buffer limit { std::string s(2000, '*'); - ws.set_option(mask_buffer_size(1200)); + ws.set_option(write_buffer_size(1200)); ws.write(buffer(s.data(), s.size())); { // receive echoed message @@ -1033,7 +1038,7 @@ public: using boost::asio::buffer; static std::size_t constexpr limit = 200; std::size_t n; - for(n = 190; n < limit; ++n) + for(n = 0; n < limit; ++n) { stream> ws(n, ios_); auto const restart = @@ -1077,7 +1082,7 @@ public: throw system_error{ec}; // send message - ws.set_option(auto_fragment_size(0)); + ws.set_option(auto_fragment{false}); ws.set_option(message_type(opcode::text)); ws.async_write(sbuf("Hello"), do_yield[ec]); if(ec) @@ -1170,9 +1175,13 @@ public: ws.set_option(pong_callback{}); } + // send pong + ws.async_pong("", do_yield[ec]); + // send auto fragmented message - ws.set_option(auto_fragment_size(3)); - ws.async_write(sbuf("Hello"), do_yield[ec]); + ws.set_option(auto_fragment{true}); + ws.set_option(write_buffer_size{8}); + ws.async_write(sbuf("Now is the time for all good men"), do_yield[ec]); { // receive echoed message opcode op; @@ -1180,14 +1189,15 @@ public: ws.async_read(op, db, do_yield[ec]); if(ec) throw system_error{ec}; - BEAST_EXPECT(to_string(db.data()) == "Hello"); + BEAST_EXPECT(to_string(db.data()) == "Now is the time for all good men"); } - ws.set_option(auto_fragment_size(0)); + ws.set_option(auto_fragment{false}); + ws.set_option(write_buffer_size{4096}); // send message with mask buffer limit { std::string s(2000, '*'); - ws.set_option(mask_buffer_size(1200)); + ws.set_option(write_buffer_size(1200)); ws.async_write(buffer(s.data(), s.size()), do_yield[ec]); if(ec) throw system_error{ec}; @@ -1379,6 +1389,9 @@ public: static_assert(! std::is_move_assignable< stream>::value, ""); + log << "sizeof(websocket::stream) == " << + sizeof(websocket::stream) << std::endl; + auto const any = endpoint_type{ address_type::from_string("127.0.0.1"), 0}; @@ -1391,13 +1404,13 @@ public: { sync_echo_server server(true, any); auto const ep = server.local_endpoint(); - + //testInvokable1(ep); testInvokable2(ep); testInvokable3(ep); testInvokable4(ep); //testInvokable5(ep); - + testSyncClient(ep); testAsyncWriteFrame(ep); yield_to_mf(ep, &stream_test::testAsyncClient); diff --git a/test/websocket/utf8_checker.cpp b/test/websocket/utf8_checker.cpp index 14749fda4..3e4055dfe 100644 --- a/test/websocket/utf8_checker.cpp +++ b/test/websocket/utf8_checker.cpp @@ -24,7 +24,7 @@ public: testOneByteSequence() { utf8_checker utf8; - std::array const buf = + std::array buf = ([]() { std::array values; @@ -47,6 +47,10 @@ public: for(auto it = std::next(buf.begin(), 245); it != buf.end(); ++it) BEAST_EXPECT(! utf8.write(&(*it), 1)); + + // Invalid sequence + std::fill(buf.begin(), buf.end(), 0xFF); + BEAST_EXPECT(! utf8.write(&buf.front(), buf.size())); } void @@ -80,6 +84,11 @@ public: buf[1] = static_cast(j); BEAST_EXPECT(! utf8.write(buf, 2)); } + + // Segmented sequence second byte invalid + BEAST_EXPECT(utf8.write(buf, 1)); + BEAST_EXPECT(! utf8.write(&buf[1], 1)); + utf8.reset(); } } @@ -106,6 +115,47 @@ public: buf[2] = static_cast(k); BEAST_EXPECT(utf8.write(buf, 3)); BEAST_EXPECT(utf8.finish()); + // Segmented sequence + BEAST_EXPECT(utf8.write(buf, 1)); + BEAST_EXPECT(utf8.write(&buf[1], 2)); + utf8.reset(); + // Segmented sequence + BEAST_EXPECT(utf8.write(buf, 2)); + BEAST_EXPECT(utf8.write(&buf[2], 1)); + utf8.reset(); + + if (i == 224) + { + for (auto l = 0; l < b; ++l) + { + // Second byte invalid range 0-127 or 0-159 + buf[1] = static_cast(l); + BEAST_EXPECT(! utf8.write(buf, 3)); + if (l > 127) + { + // Segmented sequence second byte invalid + BEAST_EXPECT(! utf8.write(buf, 2)); + utf8.reset(); + } + } + buf[1] = static_cast(j); + } + else if (i == 237) + { + for (auto l = e + 1; l <= 255; ++l) + { + // Second byte invalid range 160-255 or 192-255 + buf[1] = static_cast(l); + BEAST_EXPECT(!utf8.write(buf, 3)); + if (l > 159) + { + // Segmented sequence second byte invalid + BEAST_EXPECT(! utf8.write(buf, 2)); + utf8.reset(); + } + } + buf[1] = static_cast(j); + } } for(auto k = 0; k <= 127; ++k) @@ -121,6 +171,11 @@ public: buf[2] = static_cast(k); BEAST_EXPECT(! utf8.write(buf, 3)); } + + // Segmented sequence third byte invalid + BEAST_EXPECT(utf8.write(buf, 2)); + BEAST_EXPECT(! utf8.write(&buf[2], 1)); + utf8.reset(); } for(auto j = 0; j < b; ++j) @@ -136,6 +191,11 @@ public: buf[1] = static_cast(j); BEAST_EXPECT(! utf8.write(buf, 3)); } + + // Segmented sequence second byte invalid + BEAST_EXPECT(utf8.write(buf, 1)); + BEAST_EXPECT(! utf8.write(&buf[1], 1)); + utf8.reset(); } } @@ -154,7 +214,7 @@ public: std::int32_t const e = (i == 244 ? 143 : 191); for(auto j = b; j <= e; ++j) { - // Second byte valid range 128-191 or 144-191 or 128-143 + // Second byte valid range 144-191 or 128-191 or 128-143 buf[1] = static_cast(j); for(auto k = 128; k <= 191; ++k) @@ -168,6 +228,51 @@ public: buf[3] = static_cast(n); BEAST_EXPECT(utf8.write(const_buffers_1{buf, 4})); BEAST_EXPECT(utf8.finish()); + // Segmented sequence + BEAST_EXPECT(utf8.write(buf, 1)); + BEAST_EXPECT(utf8.write(&buf[1], 3)); + utf8.reset(); + // Segmented sequence + BEAST_EXPECT(utf8.write(buf, 2)); + BEAST_EXPECT(utf8.write(&buf[2], 2)); + utf8.reset(); + // Segmented sequence + BEAST_EXPECT(utf8.write(buf, 3)); + BEAST_EXPECT(utf8.write(&buf[3], 1)); + utf8.reset(); + + if (i == 240) + { + for (auto l = 0; l < b; ++l) + { + // Second byte invalid range 0-127 or 0-143 + buf[1] = static_cast(l); + BEAST_EXPECT(! utf8.write(buf, 4)); + if (l > 127) + { + // Segmented sequence second byte invalid + BEAST_EXPECT(! utf8.write(buf, 2)); + utf8.reset(); + } + } + buf[1] = static_cast(j); + } + else if (i == 244) + { + for (auto l = e + 1; l <= 255; ++l) + { + // Second byte invalid range 144-255 or 192-255 + buf[1] = static_cast(l); + BEAST_EXPECT(! utf8.write(buf, 4)); + if (l > 143) + { + // Segmented sequence second byte invalid + BEAST_EXPECT(! utf8.write(buf, 2)); + utf8.reset(); + } + } + buf[1] = static_cast(j); + } } for(auto n = 0; n <= 127; ++n) @@ -183,6 +288,11 @@ public: buf[3] = static_cast(n); BEAST_EXPECT(! utf8.write(buf, 4)); } + + // Segmented sequence fourth byte invalid + BEAST_EXPECT(utf8.write(buf, 3)); + BEAST_EXPECT(! utf8.write(&buf[3], 1)); + utf8.reset(); } for(auto k = 0; k <= 127; ++k) @@ -198,21 +308,38 @@ public: buf[2] = static_cast(k); BEAST_EXPECT(! utf8.write(buf, 4)); } + + // Segmented sequence third byte invalid + BEAST_EXPECT(utf8.write(buf, 2)); + BEAST_EXPECT(! utf8.write(&buf[2], 1)); + utf8.reset(); } for(auto j = 0; j < b; ++j) { // Second byte invalid range 0-127 or 0-143 buf[1] = static_cast(j); - BEAST_EXPECT(! utf8.write(buf, 3)); + BEAST_EXPECT(! utf8.write(buf, 4)); } for(auto j = e + 1; j <= 255; ++j) { // Second byte invalid range 144-255 or 192-255 buf[1] = static_cast(j); - BEAST_EXPECT(! utf8.write(buf, 3)); + BEAST_EXPECT(! utf8.write(buf, 4)); } + + // Segmented sequence second byte invalid + BEAST_EXPECT(utf8.write(buf, 1)); + BEAST_EXPECT(! utf8.write(&buf[1], 1)); + utf8.reset(); + } + + for (auto i = 245; i <= 255; ++i) + { + // First byte invalid range 245-255 + buf[0] = static_cast(i); + BEAST_EXPECT(! utf8.write(buf, 4)); } } @@ -240,20 +367,22 @@ public: 0xC3,0x81,0x72,0x76,0xC3,0xAD,0x7A,0x74,0xC5,0xB1,0x72,0xC5, 0x91,0x20,0x74,0xC3,0xBC,0x6B,0xC3,0xB6,0x72,0x66,0xC3,0xBA, 0x72,0xC3,0xB3,0x67,0xC3,0xA9,0x70 + }, { + 240, 144, 128, 128 } }; utf8_checker utf8; for(auto const& s : data) { - static std::size_t constexpr size = 8; + static std::size_t constexpr size = 3; std::size_t n = s.size(); - auto cb = consumed_buffers( - boost::asio::const_buffers_1( - s.data(), n), 0); - streambuf sb(size); + consuming_buffers< + boost::asio::const_buffers_1> cb{ + boost::asio::const_buffers_1(s.data(), n)}; + streambuf sb{size}; while(n) { - auto const amount = std::min(n, size); + auto const amount = (std::min)(n, size); sb.commit(buffer_copy(sb.prepare(amount), cb)); cb.consume(amount); n -= amount; diff --git a/test/websocket/websocket_async_echo_server.hpp b/test/websocket/websocket_async_echo_server.hpp index 35201f008..ae4963243 100644 --- a/test/websocket/websocket_async_echo_server.hpp +++ b/test/websocket/websocket_async_echo_server.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -134,18 +135,18 @@ private: struct identity { - template + template void - operator()(http::message& req) + operator()(http::message& req) { - req.headers.replace("User-Agent", "async_echo_client"); + req.fields.replace("User-Agent", "async_echo_client"); } - template + template void - operator()(http::message& resp) + operator()(http::message& resp) { - resp.headers.replace("Server", "async_echo_server"); + resp.fields.replace("Server", "async_echo_server"); } }; @@ -277,7 +278,7 @@ private: d.state = 1; d.ws.async_handshake( d.ep->address().to_string() + ":" + - std::to_string(d.ep->port()), + boost::lexical_cast(d.ep->port()), "/", d.strand.wrap(std::move(*this))); return; } diff --git a/test/websocket/websocket_sync_echo_server.hpp b/test/websocket/websocket_sync_echo_server.hpp index a09e47504..97276292f 100644 --- a/test/websocket/websocket_sync_echo_server.hpp +++ b/test/websocket/websocket_sync_echo_server.hpp @@ -8,8 +8,10 @@ #ifndef BEAST_WEBSOCKET_SYNC_ECHO_PEER_H_INCLUDED #define BEAST_WEBSOCKET_SYNC_ECHO_PEER_H_INCLUDED +#include #include #include +#include #include #include #include @@ -36,7 +38,7 @@ private: std::thread thread_; public: - sync_echo_server(bool server, endpoint_type ep) + sync_echo_server(bool /*server*/, endpoint_type ep) : sock_(ios_) , acceptor_(ios_) { @@ -83,7 +85,7 @@ private: fail(int id, error_code ec, std::string what) { if(log_) - std::cerr << "#" << std::to_string(id) << " " << + std::cerr << "#" << boost::lexical_cast(id) << " " << what << ": " << ec.message() << std::endl; } @@ -136,18 +138,18 @@ private: struct identity { - template + template void - operator()(http::message& req) + operator()(http::message& req) { - req.headers.replace("User-Agent", "sync_echo_client"); + req.fields.replace("User-Agent", "sync_echo_client"); } - template + template void - operator()(http::message& resp) + operator()(http::message& resp) { - resp.headers.replace("Server", "sync_echo_server"); + resp.fields.replace("Server", "sync_echo_server"); } }; diff --git a/test/zlib.cpp b/test/zlib.cpp new file mode 100644 index 000000000..9254354a4 --- /dev/null +++ b/test/zlib.cpp @@ -0,0 +1,9 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Test that header file is self-contained. +#include diff --git a/test/zlib/CMakeLists.txt b/test/zlib/CMakeLists.txt new file mode 100644 index 000000000..3c0f2035b --- /dev/null +++ b/test/zlib/CMakeLists.txt @@ -0,0 +1,47 @@ +# Part of Beast + +GroupSources(extras/beast extras) +GroupSources(include/beast beast) +GroupSources(test/zlib "/") + +set(ZLIB_SOURCES + zlib-1.2.8/crc32.h + zlib-1.2.8/deflate.h + zlib-1.2.8/inffast.h + zlib-1.2.8/inffixed.h + zlib-1.2.8/inflate.h + zlib-1.2.8/inftrees.h + zlib-1.2.8/trees.h + zlib-1.2.8/zlib.h + zlib-1.2.8/zutil.h + zlib-1.2.8/adler32.c + zlib-1.2.8/compress.c + zlib-1.2.8/crc32.c + zlib-1.2.8/deflate.c + zlib-1.2.8/infback.c + zlib-1.2.8/inffast.c + zlib-1.2.8/inflate.c + zlib-1.2.8/inftrees.c + zlib-1.2.8/trees.c + zlib-1.2.8/uncompr.c + zlib-1.2.8/zutil.c +) + +if (MSVC) + set_source_files_properties (${ZLIB_SOURCES} PROPERTIES COMPILE_FLAGS "/wd4127 /wd4131 /wd4244") +endif() + +add_executable (zlib-tests + ${BEAST_INCLUDES} + ${EXTRAS_INCLUDES} + ${ZLIB_SOURCES} + ../../extras/beast/unit_test/main.cpp + ztest.hpp + deflate_stream.cpp + error.cpp + inflate_stream.cpp +) + +if (NOT WIN32) + target_link_libraries(zlib-tests ${Boost_LIBRARIES} Threads::Threads) +endif() diff --git a/test/zlib/deflate_stream.cpp b/test/zlib/deflate_stream.cpp new file mode 100644 index 000000000..613606c70 --- /dev/null +++ b/test/zlib/deflate_stream.cpp @@ -0,0 +1,336 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Test that header file is self-contained. +#include + +#include "ztest.hpp" +#include + +namespace beast { +namespace zlib { + +class deflate_stream_test : public beast::unit_test::suite +{ +public: + using self = deflate_stream_test; + typedef void(self::*pmf_t)( + int level, int windowBits, int strategy, + std::string const&); + + static + Strategy + toStrategy(int strategy) + { + switch(strategy) + { + default: + case 0: return Strategy::normal; + case 1: return Strategy::filtered; + case 2: return Strategy::huffman; + case 3: return Strategy::rle; + case 4: return Strategy::fixed; + } + } + + void + doDeflate1_zlib( + int level, int windowBits, int strategy, + std::string const& check) + { + int result; + std::string out; + ::z_stream zs; + std::memset(&zs, 0, sizeof(zs)); + result = deflateInit2(&zs, + level, + Z_DEFLATED, + -windowBits, + 8, + strategy); + if(! BEAST_EXPECT(result == Z_OK)) + goto err; + out.resize(deflateBound(&zs, + static_cast(check.size()))); + zs.next_in = (Bytef*)check.data(); + zs.avail_in = static_cast(check.size()); + zs.next_out = (Bytef*)out.data(); + zs.avail_out = static_cast(out.size()); + { + bool progress = true; + for(;;) + { + result = deflate(&zs, Z_FULL_FLUSH); + if( result == Z_BUF_ERROR || + result == Z_STREAM_END) // per zlib FAQ + goto fin; + if(! BEAST_EXPECT(progress)) + goto err; + progress = false; + } + } + + fin: + out.resize(zs.total_out); + { + z_inflator zi; + auto const s = zi(out); + BEAST_EXPECT(s == check); + } + + err: + deflateEnd(&zs); + } + + void + doDeflate1_beast( + int level, int windowBits, int strategy, + std::string const& check) + { + std::string out; + z_params zs; + deflate_stream ds; + ds.reset( + level, + windowBits, + 8, + toStrategy(strategy)); + out.resize(ds.upper_bound( + static_cast(check.size()))); + zs.next_in = (Bytef*)check.data(); + zs.avail_in = static_cast(check.size()); + zs.next_out = (Bytef*)out.data(); + zs.avail_out = static_cast(out.size()); + { + bool progress = true; + for(;;) + { + error_code ec; + ds.write(zs, Flush::full, ec); + if( ec == error::need_buffers || + ec == error::end_of_stream) // per zlib FAQ + goto fin; + if(! BEAST_EXPECTS(! ec, ec.message())) + goto err; + if(! BEAST_EXPECT(progress)) + goto err; + progress = false; + } + } + + fin: + out.resize(zs.total_out); + { + z_inflator zi; + auto const s = zi(out); + BEAST_EXPECT(s == check); + } + + err: + ; + } + + //-------------------------------------------------------------------------- + + void + doDeflate2_zlib( + int level, int windowBits, int strategy, + std::string const& check) + { + for(std::size_t i = 1; i < check.size(); ++i) + { + for(std::size_t j = 1;; ++j) + { + int result; + ::z_stream zs; + std::memset(&zs, 0, sizeof(zs)); + result = deflateInit2(&zs, + level, + Z_DEFLATED, + -windowBits, + 8, + strategy); + if(! BEAST_EXPECT(result == Z_OK)) + continue; + std::string out; + out.resize(deflateBound(&zs, + static_cast(check.size()))); + if(j >= out.size()) + { + deflateEnd(&zs); + break; + } + zs.next_in = (Bytef*)check.data(); + zs.avail_in = static_cast(i); + zs.next_out = (Bytef*)out.data(); + zs.avail_out = static_cast(j); + bool bi = false; + bool bo = false; + for(;;) + { + int flush = bi ? Z_FULL_FLUSH : Z_NO_FLUSH; + result = deflate(&zs, flush); + if( result == Z_BUF_ERROR || + result == Z_STREAM_END) // per zlib FAQ + goto fin; + if(! BEAST_EXPECT(result == Z_OK)) + goto err; + if(zs.avail_in == 0 && ! bi) + { + bi = true; + zs.avail_in = + static_cast(check.size() - i); + } + if(zs.avail_out == 0 && ! bo) + { + bo = true; + zs.avail_out = + static_cast(out.size() - j); + } + } + + fin: + out.resize(zs.total_out); + { + z_inflator zi; + auto const s = zi(out); + BEAST_EXPECT(s == check); + } + + err: + deflateEnd(&zs); + } + } + } + + void + doDeflate2_beast( + int level, int windowBits, int strategy, + std::string const& check) + { + for(std::size_t i = 1; i < check.size(); ++i) + { + for(std::size_t j = 1;; ++j) + { + z_params zs; + deflate_stream ds; + ds.reset( + level, + windowBits, + 8, + toStrategy(strategy)); + std::string out; + out.resize(ds.upper_bound( + static_cast(check.size()))); + if(j >= out.size()) + break; + zs.next_in = (Bytef*)check.data(); + zs.avail_in = static_cast(i); + zs.next_out = (Bytef*)out.data(); + zs.avail_out = static_cast(j); + bool bi = false; + bool bo = false; + for(;;) + { + error_code ec; + ds.write(zs, + bi ? Flush::full : Flush::none, ec); + if( ec == error::need_buffers || + ec == error::end_of_stream) // per zlib FAQ + goto fin; + if(! BEAST_EXPECTS(! ec, ec.message())) + goto err; + if(zs.avail_in == 0 && ! bi) + { + bi = true; + zs.avail_in = + static_cast(check.size() - i); + } + if(zs.avail_out == 0 && ! bo) + { + bo = true; + zs.avail_out = + static_cast(out.size() - j); + } + } + + fin: + out.resize(zs.total_out); + { + z_inflator zi; + auto const s = zi(out); + BEAST_EXPECT(s == check); + } + + err: + ; + } + } + } + + //-------------------------------------------------------------------------- + + void + doMatrix(std::string const& label, + std::string const& check, pmf_t pmf) + { + using namespace std::chrono; + using clock_type = steady_clock; + auto const when = clock_type::now(); + for(int level = 0; level <= 9; ++level) + { + for(int windowBits = 8; windowBits <= 9; ++windowBits) + { + for(int strategy = 0; strategy <= 4; ++strategy) + { + (this->*pmf)( + level, windowBits, strategy, check); + } + } + } + auto const elapsed = clock_type::now() - when; + log << + label << ": " << + duration_cast< + milliseconds>(elapsed).count() << "ms\n"; + log.flush(); + } + + void + testDeflate() + { + doMatrix("1.beast ", "Hello, world!", &self::doDeflate1_beast); + doMatrix("1.zlib ", "Hello, world!", &self::doDeflate1_zlib); + doMatrix("2.beast ", "Hello, world!", &self::doDeflate2_beast); + doMatrix("2.zlib ", "Hello, world!", &self::doDeflate2_zlib); + { + auto const s = corpus1(56); + doMatrix("3.beast ", s, &self::doDeflate2_beast); + doMatrix("3.zlib ", s, &self::doDeflate2_zlib); + } + { + auto const s = corpus1(512 * 1024); + doMatrix("4.beast ", s, &self::doDeflate1_beast); + doMatrix("4.zlib ", s, &self::doDeflate1_zlib); + } + } + + void + run() override + { + log << + "sizeof(deflate_stream) == " << + sizeof(deflate_stream) << std::endl; + + testDeflate(); + } +}; + +BEAST_DEFINE_TESTSUITE(deflate_stream,core,beast); + +} // zlib +} // beast diff --git a/test/zlib/error.cpp b/test/zlib/error.cpp new file mode 100644 index 000000000..247b1ecf6 --- /dev/null +++ b/test/zlib/error.cpp @@ -0,0 +1,61 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Test that header file is self-contained. +#include + +#include +#include + +namespace beast { +namespace zlib { + +class error_test : public unit_test::suite +{ +public: + void check(char const* name, error ev) + { + auto const ec = make_error_code(ev); + BEAST_EXPECT(std::string{ec.category().name()} == name); + BEAST_EXPECT(! ec.message().empty()); + BEAST_EXPECT(std::addressof(ec.category()) == + std::addressof(detail::get_error_category())); + BEAST_EXPECT(detail::get_error_category().equivalent( + static_cast::type>(ev), + ec.category().default_error_condition( + static_cast::type>(ev)))); + BEAST_EXPECT(detail::get_error_category().equivalent( + ec, static_cast::type>(ev))); + } + + void run() override + { + check("zlib", error::need_buffers); + check("zlib", error::end_of_stream); + check("zlib", error::stream_error); + + check("zlib", error::invalid_block_type); + check("zlib", error::invalid_stored_length); + check("zlib", error::too_many_symbols); + check("zlib", error::invalid_code_lenths); + check("zlib", error::invalid_bit_length_repeat); + check("zlib", error::missing_eob); + check("zlib", error::invalid_literal_length); + check("zlib", error::invalid_distance_code); + check("zlib", error::invalid_distance); + + check("zlib", error::over_subscribed_length); + check("zlib", error::incomplete_length_set); + + check("zlib", error::general); + } +}; + +BEAST_DEFINE_TESTSUITE(error,zlib,beast); + +} // zlib +} // beast diff --git a/test/zlib/inflate_stream.cpp b/test/zlib/inflate_stream.cpp new file mode 100644 index 000000000..df72860d1 --- /dev/null +++ b/test/zlib/inflate_stream.cpp @@ -0,0 +1,412 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +// Test that header file is self-contained. +#include + +#include "ztest.hpp" +#include +#include +#include + +namespace beast { +namespace zlib { + +class inflate_stream_test : public beast::unit_test::suite +{ +public: + //-------------------------------------------------------------------------- + + enum Split + { + once, + half, + full + }; + + class Beast + { + Split in_; + Split check_; + Flush flush_; + + public: + Beast(Split in, Split check, Flush flush = Flush::sync) + : in_(in) + , check_(check) + , flush_(flush) + { + } + + void + operator()( + int window, + std::string const& in, + std::string const& check, + unit_test::suite& suite) const + { + auto const f = + [&](std::size_t i, std::size_t j) + { + std::string out(check.size(), 0); + z_params zs; + zs.next_in = in.data(); + zs.next_out = &out[0]; + zs.avail_in = i; + zs.avail_out = j; + inflate_stream is; + is.reset(window); + bool bi = ! (i < in.size()); + bool bo = ! (j < check.size()); + for(;;) + { + error_code ec; + is.write(zs, flush_, ec); + if( ec == error::need_buffers || + ec == error::end_of_stream) + { + out.resize(zs.total_out); + suite.expect(out == check, __FILE__, __LINE__); + break; + } + if(ec) + { + suite.fail(ec.message(), __FILE__, __LINE__); + break; + } + if(zs.avail_in == 0 && ! bi) + { + bi = true; + zs.avail_in = in.size() - i; + } + if(zs.avail_out == 0 && ! bo) + { + bo = true; + zs.avail_out = check.size() - j; + } + } + }; + + std::size_t i0, i1; + std::size_t j0, j1; + + switch(in_) + { + default: + case once: i0 = in.size(); i1 = i0; break; + case half: i0 = in.size() / 2; i1 = i0; break; + case full: i0 = 1; i1 = in.size(); break; + } + + switch(check_) + { + default: + case once: j0 = check.size(); j1 = j0; break; + case half: j0 = check.size() / 2; j1 = j0; break; + case full: j0 = 1; j1 = check.size(); break; + } + + for(std::size_t i = i0; i <= i1; ++i) + for(std::size_t j = j0; j <= j1; ++j) + f(i, j); + } + }; + + class ZLib + { + Split in_; + Split check_; + int flush_; + + public: + ZLib(Split in, Split check, int flush = Z_SYNC_FLUSH) + : in_(in) + , check_(check) + , flush_(flush) + { + } + + void + operator()( + int window, + std::string const& in, + std::string const& check, + unit_test::suite& suite) const + { + auto const f = + [&](std::size_t i, std::size_t j) + { + int result; + std::string out(check.size(), 0); + ::z_stream zs; + memset(&zs, 0, sizeof(zs)); + result = inflateInit2(&zs, -window); + if(result != Z_OK) + { + suite.fail("! Z_OK", __FILE__, __LINE__); + return; + } + zs.next_in = (Bytef*)in.data(); + zs.next_out = (Bytef*)out.data(); + zs.avail_in = static_cast(i); + zs.avail_out = static_cast(j); + bool bi = ! (i < in.size()); + bool bo = ! (j < check.size()); + for(;;) + { + result = inflate(&zs, flush_); + if( result == Z_BUF_ERROR || + result == Z_STREAM_END) // per zlib FAQ + { + out.resize(zs.total_out); + suite.expect(out == check, __FILE__, __LINE__); + break; + } + if(result != Z_OK) + { + suite.fail("! Z_OK", __FILE__, __LINE__); + break; + } + if(zs.avail_in == 0 && ! bi) + { + bi = true; + zs.avail_in = static_cast(in.size() - i); + } + if(zs.avail_out == 0 && ! bo) + { + bo = true; + zs.avail_out = static_cast(check.size() - j); + } + } + inflateEnd(&zs); + }; + + std::size_t i0, i1; + std::size_t j0, j1; + + switch(in_) + { + default: + case once: i0 = in.size(); i1 = i0; break; + case half: i0 = in.size() / 2; i1 = i0; break; + case full: i0 = 1; i1 = in.size(); break; + } + + switch(check_) + { + default: + case once: j0 = check.size(); j1 = j0; break; + case half: j0 = check.size() / 2; j1 = j0; break; + case full: j0 = 1; j1 = check.size(); break; + } + + for(std::size_t i = i0; i <= i1; ++i) + for(std::size_t j = j0; j <= j1; ++j) + f(i, j); + } + }; + + class Matrix + { + unit_test::suite& suite_; + + int level_[2]; + int window_[2]; + int strategy_[2]; + + public: + explicit + Matrix(unit_test::suite& suite) + : suite_(suite) + { + level_[0] = 0; + level_[1] = 9; + window_[0] = 8; + window_[1] = 15; + strategy_[0] = 0; + strategy_[1] = 4; + } + + void + level(int from, int to) + { + level_[0] = from; + level_[1] = to; + } + + void + level(int what) + { + level(what, what); + } + + void + window(int from, int to) + { + window_[0] = from; + window_[1] = to; + } + + void + window(int what) + { + window(what, what); + } + + void + strategy(int from, int to) + { + strategy_[0] = from; + strategy_[1] = to; + } + + void + strategy(int what) + { + strategy(what, what); + } + + template + void + operator()( + std::string label, + F const& f, + std::string const& check) const + { + using namespace std::chrono; + using clock_type = steady_clock; + auto const when = clock_type::now(); + + for(auto level = level_[0]; + level <= level_[1]; ++level) + { + for(auto window = window_[0]; + window <= window_[1]; ++window) + { + for(auto strategy = strategy_[0]; + strategy <= strategy_[1]; ++strategy) + { + z_deflator zd; + zd.level(level); + zd.windowBits(window); + zd.strategy(strategy); + auto const in = zd(check); + f(window, in, check, suite_); + } + } + } + auto const elapsed = clock_type::now() - when; + suite_.log << + label << ": " << + duration_cast< + milliseconds>(elapsed).count() << "ms\n"; + suite_.log.flush(); + } + }; + + void + testInflate() + { + { + Matrix m{*this}; + std::string check = + "{\n \"AutobahnPython/0.6.0\": {\n" + " \"1.1.1\": {\n" + " \"behavior\": \"OK\",\n" + " \"behaviorClose\": \"OK\",\n" + " \"duration\": 2,\n" + " \"remoteCloseCode\": 1000,\n" + " \"reportfile\": \"autobahnpython_0_6_0_case_1_1_1.json\"\n" + ; + m("1. beast", Beast{half, half}, check); + m("1. zlib ", ZLib {half, half}, check); + } + { + Matrix m{*this}; + auto const check = corpus1(50000); + m("2. beast", Beast{half, half}, check); + m("2. zlib ", ZLib {half, half}, check); + } + { + Matrix m{*this}; + auto const check = corpus2(50000); + m("3. beast", Beast{half, half}, check); + m("3. zlib ", ZLib {half, half}, check); + } + { + Matrix m{*this}; + auto const check = corpus1(10000); + m.level(6); + m.window(9); + m.strategy(Z_DEFAULT_STRATEGY); + m("4. beast", Beast{once, full}, check); + m("4. zlib ", ZLib {once, full}, check); + } + { + Matrix m{*this}; + auto const check = corpus2(10000); + m.level(6); + m.window(9); + m.strategy(Z_DEFAULT_STRATEGY); + m("5. beast", Beast{once, full}, check); + m("5. zlib ", ZLib {once, full}, check); + } + { + Matrix m{*this}; + m.level(6); + m.window(9); + auto const check = corpus1(200); + m("6. beast", Beast{full, full}, check); + m("6. zlib ", ZLib {full, full}, check); + } + { + Matrix m{*this}; + m.level(6); + m.window(9); + auto const check = corpus2(500); + m("7. beast", Beast{full, full}, check); + m("7. zlib ", ZLib {full, full}, check); + } + { + Matrix m{*this}; + auto const check = corpus2(10000); + m.level(6); + m.window(9); + m.strategy(Z_DEFAULT_STRATEGY); + m("8. beast", Beast{full, once, Flush::block}, check); + m("8. zlib ", ZLib {full, once, Z_BLOCK}, check); + } + + // VFALCO Fails, but I'm unsure of what the correct + // behavior of Z_TREES/Flush::trees is. +#if 0 + { + Matrix m{*this}; + auto const check = corpus2(10000); + m.level(6); + m.window(9); + m.strategy(Z_DEFAULT_STRATEGY); + m("9. beast", Beast{full, once, Flush::trees}, check); + m("9. zlib ", ZLib {full, once, Z_TREES}, check); + } +#endif + } + + void + run() override + { + log << + "sizeof(inflate_stream) == " << + sizeof(inflate_stream) << std::endl; + testInflate(); + } +}; + +BEAST_DEFINE_TESTSUITE(inflate_stream,core,beast); + +} // zlib +} // beast diff --git a/test/zlib/zlib-1.2.8/CMakeLists.txt b/test/zlib/zlib-1.2.8/CMakeLists.txt new file mode 100644 index 000000000..0c0247cc5 --- /dev/null +++ b/test/zlib/zlib-1.2.8/CMakeLists.txt @@ -0,0 +1,249 @@ +cmake_minimum_required(VERSION 2.4.4) +set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) + +project(zlib C) + +set(VERSION "1.2.8") + +option(ASM686 "Enable building i686 assembly implementation") +option(AMD64 "Enable building amd64 assembly implementation") + +set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables") +set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries") +set(INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for headers") +set(INSTALL_MAN_DIR "${CMAKE_INSTALL_PREFIX}/share/man" CACHE PATH "Installation directory for manual pages") +set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files") + +include(CheckTypeSize) +include(CheckFunctionExists) +include(CheckIncludeFile) +include(CheckCSourceCompiles) +enable_testing() + +check_include_file(sys/types.h HAVE_SYS_TYPES_H) +check_include_file(stdint.h HAVE_STDINT_H) +check_include_file(stddef.h HAVE_STDDEF_H) + +# +# Check to see if we have large file support +# +set(CMAKE_REQUIRED_DEFINITIONS -D_LARGEFILE64_SOURCE=1) +# We add these other definitions here because CheckTypeSize.cmake +# in CMake 2.4.x does not automatically do so and we want +# compatibility with CMake 2.4.x. +if(HAVE_SYS_TYPES_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_SYS_TYPES_H) +endif() +if(HAVE_STDINT_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDINT_H) +endif() +if(HAVE_STDDEF_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDDEF_H) +endif() +check_type_size(off64_t OFF64_T) +if(HAVE_OFF64_T) + add_definitions(-D_LARGEFILE64_SOURCE=1) +endif() +set(CMAKE_REQUIRED_DEFINITIONS) # clear variable + +# +# Check for fseeko +# +check_function_exists(fseeko HAVE_FSEEKO) +if(NOT HAVE_FSEEKO) + add_definitions(-DNO_FSEEKO) +endif() + +# +# Check for unistd.h +# +check_include_file(unistd.h Z_HAVE_UNISTD_H) + +if(MSVC) + set(CMAKE_DEBUG_POSTFIX "d") + add_definitions(-D_CRT_SECURE_NO_DEPRECATE) + add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE) + include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +endif() + +if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) + # If we're doing an out of source build and the user has a zconf.h + # in their source tree... + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h) + message(STATUS "Renaming") + message(STATUS " ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h") + message(STATUS "to 'zconf.h.included' because this file is included with zlib") + message(STATUS "but CMake generates it automatically in the build directory.") + file(RENAME ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.included) + endif() +endif() + +set(ZLIB_PC ${CMAKE_CURRENT_BINARY_DIR}/zlib.pc) +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zlib.pc.cmakein + ${ZLIB_PC} @ONLY) +configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.cmakein + ${CMAKE_CURRENT_BINARY_DIR}/zconf.h @ONLY) +include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}) + + +#============================================================================ +# zlib +#============================================================================ + +set(ZLIB_PUBLIC_HDRS + ${CMAKE_CURRENT_BINARY_DIR}/zconf.h + zlib.h +) +set(ZLIB_PRIVATE_HDRS + crc32.h + deflate.h + gzguts.h + inffast.h + inffixed.h + inflate.h + inftrees.h + trees.h + zutil.h +) +set(ZLIB_SRCS + adler32.c + compress.c + crc32.c + deflate.c + gzclose.c + gzlib.c + gzread.c + gzwrite.c + inflate.c + infback.c + inftrees.c + inffast.c + trees.c + uncompr.c + zutil.c +) + +if(NOT MINGW) + set(ZLIB_DLL_SRCS + win32/zlib1.rc # If present will override custom build rule below. + ) +endif() + +if(CMAKE_COMPILER_IS_GNUCC) + if(ASM686) + set(ZLIB_ASMS contrib/asm686/match.S) + elseif (AMD64) + set(ZLIB_ASMS contrib/amd64/amd64-match.S) + endif () + + if(ZLIB_ASMS) + add_definitions(-DASMV) + set_source_files_properties(${ZLIB_ASMS} PROPERTIES LANGUAGE C COMPILE_FLAGS -DNO_UNDERLINE) + endif() +endif() + +if(MSVC) + if(ASM686) + ENABLE_LANGUAGE(ASM_MASM) + set(ZLIB_ASMS + contrib/masmx86/inffas32.asm + contrib/masmx86/match686.asm + ) + elseif (AMD64) + ENABLE_LANGUAGE(ASM_MASM) + set(ZLIB_ASMS + contrib/masmx64/gvmat64.asm + contrib/masmx64/inffasx64.asm + ) + endif() + + if(ZLIB_ASMS) + add_definitions(-DASMV -DASMINF) + endif() +endif() + +# parse the full version number from zlib.h and include in ZLIB_FULL_VERSION +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents) +string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*" + "\\1" ZLIB_FULL_VERSION ${_zlib_h_contents}) + +if(MINGW) + # This gets us DLL resource information when compiling on MinGW. + if(NOT CMAKE_RC_COMPILER) + set(CMAKE_RC_COMPILER windres.exe) + endif() + + add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj + COMMAND ${CMAKE_RC_COMPILER} + -D GCC_WINDRES + -I ${CMAKE_CURRENT_SOURCE_DIR} + -I ${CMAKE_CURRENT_BINARY_DIR} + -o ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj + -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zlib1.rc) + set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) +endif(MINGW) + +add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL) +set_target_properties(zlib PROPERTIES SOVERSION 1) + +if(NOT CYGWIN) + # This property causes shared libraries on Linux to have the full version + # encoded into their final filename. We disable this on Cygwin because + # it causes cygz-${ZLIB_FULL_VERSION}.dll to be created when cygz.dll + # seems to be the default. + # + # This has no effect with MSVC, on that platform the version info for + # the DLL comes from the resource file win32/zlib1.rc + set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION}) +endif() + +if(UNIX) + # On unix-like platforms the library is almost always called libz + set_target_properties(zlib zlibstatic PROPERTIES OUTPUT_NAME z) + if(NOT APPLE) + set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"") + endif() +elseif(BUILD_SHARED_LIBS AND WIN32) + # Creates zlib1.dll when building shared library version + set_target_properties(zlib PROPERTIES SUFFIX "1.dll") +endif() + +if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL ) + install(TARGETS zlib zlibstatic + RUNTIME DESTINATION "${INSTALL_BIN_DIR}" + ARCHIVE DESTINATION "${INSTALL_LIB_DIR}" + LIBRARY DESTINATION "${INSTALL_LIB_DIR}" ) +endif() +if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL ) + install(FILES ${ZLIB_PUBLIC_HDRS} DESTINATION "${INSTALL_INC_DIR}") +endif() +if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) + install(FILES zlib.3 DESTINATION "${INSTALL_MAN_DIR}/man3") +endif() +if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL ) + install(FILES ${ZLIB_PC} DESTINATION "${INSTALL_PKGCONFIG_DIR}") +endif() + +#============================================================================ +# Example binaries +#============================================================================ + +add_executable(example test/example.c) +target_link_libraries(example zlib) +add_test(example example) + +add_executable(minigzip test/minigzip.c) +target_link_libraries(minigzip zlib) + +if(HAVE_OFF64_T) + add_executable(example64 test/example.c) + target_link_libraries(example64 zlib) + set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") + add_test(example64 example64) + + add_executable(minigzip64 test/minigzip.c) + target_link_libraries(minigzip64 zlib) + set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") +endif() diff --git a/test/zlib/zlib-1.2.8/ChangeLog b/test/zlib/zlib-1.2.8/ChangeLog new file mode 100644 index 000000000..f22aabaef --- /dev/null +++ b/test/zlib/zlib-1.2.8/ChangeLog @@ -0,0 +1,1472 @@ + + ChangeLog file for zlib + +Changes in 1.2.8 (28 Apr 2013) +- Update contrib/minizip/iowin32.c for Windows RT [Vollant] +- Do not force Z_CONST for C++ +- Clean up contrib/vstudio [Ro§] +- Correct spelling error in zlib.h +- Fix mixed line endings in contrib/vstudio + +Changes in 1.2.7.3 (13 Apr 2013) +- Fix version numbers and DLL names in contrib/vstudio/*/zlib.rc + +Changes in 1.2.7.2 (13 Apr 2013) +- Change check for a four-byte type back to hexadecimal +- Fix typo in win32/Makefile.msc +- Add casts in gzwrite.c for pointer differences + +Changes in 1.2.7.1 (24 Mar 2013) +- Replace use of unsafe string functions with snprintf if available +- Avoid including stddef.h on Windows for Z_SOLO compile [Niessink] +- Fix gzgetc undefine when Z_PREFIX set [Turk] +- Eliminate use of mktemp in Makefile (not always available) +- Fix bug in 'F' mode for gzopen() +- Add inflateGetDictionary() function +- Correct comment in deflate.h +- Use _snprintf for snprintf in Microsoft C +- On Darwin, only use /usr/bin/libtool if libtool is not Apple +- Delete "--version" file if created by "ar --version" [Richard G.] +- Fix configure check for veracity of compiler error return codes +- Fix CMake compilation of static lib for MSVC2010 x64 +- Remove unused variable in infback9.c +- Fix argument checks in gzlog_compress() and gzlog_write() +- Clean up the usage of z_const and respect const usage within zlib +- Clean up examples/gzlog.[ch] comparisons of different types +- Avoid shift equal to bits in type (caused endless loop) +- Fix unintialized value bug in gzputc() introduced by const patches +- Fix memory allocation error in examples/zran.c [Nor] +- Fix bug where gzopen(), gzclose() would write an empty file +- Fix bug in gzclose() when gzwrite() runs out of memory +- Check for input buffer malloc failure in examples/gzappend.c +- Add note to contrib/blast to use binary mode in stdio +- Fix comparisons of differently signed integers in contrib/blast +- Check for invalid code length codes in contrib/puff +- Fix serious but very rare decompression bug in inftrees.c +- Update inflateBack() comments, since inflate() can be faster +- Use underscored I/O function names for WINAPI_FAMILY +- Add _tr_flush_bits to the external symbols prefixed by --zprefix +- Add contrib/vstudio/vc10 pre-build step for static only +- Quote --version-script argument in CMakeLists.txt +- Don't specify --version-script on Apple platforms in CMakeLists.txt +- Fix casting error in contrib/testzlib/testzlib.c +- Fix types in contrib/minizip to match result of get_crc_table() +- Simplify contrib/vstudio/vc10 with 'd' suffix +- Add TOP support to win32/Makefile.msc +- Suport i686 and amd64 assembler builds in CMakeLists.txt +- Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h +- Add vc11 and vc12 build files to contrib/vstudio +- Add gzvprintf() as an undocumented function in zlib +- Fix configure for Sun shell +- Remove runtime check in configure for four-byte integer type +- Add casts and consts to ease user conversion to C++ +- Add man pages for minizip and miniunzip +- In Makefile uninstall, don't rm if preceding cd fails +- Do not return Z_BUF_ERROR if deflateParam() has nothing to write + +Changes in 1.2.7 (2 May 2012) +- Replace use of memmove() with a simple copy for portability +- Test for existence of strerror +- Restore gzgetc_ for backward compatibility with 1.2.6 +- Fix build with non-GNU make on Solaris +- Require gcc 4.0 or later on Mac OS X to use the hidden attribute +- Include unistd.h for Watcom C +- Use __WATCOMC__ instead of __WATCOM__ +- Do not use the visibility attribute if NO_VIZ defined +- Improve the detection of no hidden visibility attribute +- Avoid using __int64 for gcc or solo compilation +- Cast to char * in gzprintf to avoid warnings [Zinser] +- Fix make_vms.com for VAX [Zinser] +- Don't use library or built-in byte swaps +- Simplify test and use of gcc hidden attribute +- Fix bug in gzclose_w() when gzwrite() fails to allocate memory +- Add "x" (O_EXCL) and "e" (O_CLOEXEC) modes support to gzopen() +- Fix bug in test/minigzip.c for configure --solo +- Fix contrib/vstudio project link errors [Mohanathas] +- Add ability to choose the builder in make_vms.com [Schweda] +- Add DESTDIR support to mingw32 win32/Makefile.gcc +- Fix comments in win32/Makefile.gcc for proper usage +- Allow overriding the default install locations for cmake +- Generate and install the pkg-config file with cmake +- Build both a static and a shared version of zlib with cmake +- Include version symbols for cmake builds +- If using cmake with MSVC, add the source directory to the includes +- Remove unneeded EXTRA_CFLAGS from win32/Makefile.gcc [Truta] +- Move obsolete emx makefile to old [Truta] +- Allow the use of -Wundef when compiling or using zlib +- Avoid the use of the -u option with mktemp +- Improve inflate() documentation on the use of Z_FINISH +- Recognize clang as gcc +- Add gzopen_w() in Windows for wide character path names +- Rename zconf.h in CMakeLists.txt to move it out of the way +- Add source directory in CMakeLists.txt for building examples +- Look in build directory for zlib.pc in CMakeLists.txt +- Remove gzflags from zlibvc.def in vc9 and vc10 +- Fix contrib/minizip compilation in the MinGW environment +- Update ./configure for Solaris, support --64 [Mooney] +- Remove -R. from Solaris shared build (possible security issue) +- Avoid race condition for parallel make (-j) running example +- Fix type mismatch between get_crc_table() and crc_table +- Fix parsing of version with "-" in CMakeLists.txt [Snider, Ziegler] +- Fix the path to zlib.map in CMakeLists.txt +- Force the native libtool in Mac OS X to avoid GNU libtool [Beebe] +- Add instructions to win32/Makefile.gcc for shared install [Torri] + +Changes in 1.2.6.1 (12 Feb 2012) +- Avoid the use of the Objective-C reserved name "id" +- Include io.h in gzguts.h for Microsoft compilers +- Fix problem with ./configure --prefix and gzgetc macro +- Include gz_header definition when compiling zlib solo +- Put gzflags() functionality back in zutil.c +- Avoid library header include in crc32.c for Z_SOLO +- Use name in GCC_CLASSIC as C compiler for coverage testing, if set +- Minor cleanup in contrib/minizip/zip.c [Vollant] +- Update make_vms.com [Zinser] +- Remove unnecessary gzgetc_ function +- Use optimized byte swap operations for Microsoft and GNU [Snyder] +- Fix minor typo in zlib.h comments [Rzesniowiecki] + +Changes in 1.2.6 (29 Jan 2012) +- Update the Pascal interface in contrib/pascal +- Fix function numbers for gzgetc_ in zlibvc.def files +- Fix configure.ac for contrib/minizip [Schiffer] +- Fix large-entry detection in minizip on 64-bit systems [Schiffer] +- Have ./configure use the compiler return code for error indication +- Fix CMakeLists.txt for cross compilation [McClure] +- Fix contrib/minizip/zip.c for 64-bit architectures [Dalsnes] +- Fix compilation of contrib/minizip on FreeBSD [Marquez] +- Correct suggested usages in win32/Makefile.msc [Shachar, Horvath] +- Include io.h for Turbo C / Borland C on all platforms [Truta] +- Make version explicit in contrib/minizip/configure.ac [Bosmans] +- Avoid warning for no encryption in contrib/minizip/zip.c [Vollant] +- Minor cleanup up contrib/minizip/unzip.c [Vollant] +- Fix bug when compiling minizip with C++ [Vollant] +- Protect for long name and extra fields in contrib/minizip [Vollant] +- Avoid some warnings in contrib/minizip [Vollant] +- Add -I../.. -L../.. to CFLAGS for minizip and miniunzip +- Add missing libs to minizip linker command +- Add support for VPATH builds in contrib/minizip +- Add an --enable-demos option to contrib/minizip/configure +- Add the generation of configure.log by ./configure +- Exit when required parameters not provided to win32/Makefile.gcc +- Have gzputc return the character written instead of the argument +- Use the -m option on ldconfig for BSD systems [Tobias] +- Correct in zlib.map when deflateResetKeep was added + +Changes in 1.2.5.3 (15 Jan 2012) +- Restore gzgetc function for binary compatibility +- Do not use _lseeki64 under Borland C++ [Truta] +- Update win32/Makefile.msc to build test/*.c [Truta] +- Remove old/visualc6 given CMakefile and other alternatives +- Update AS400 build files and documentation [Monnerat] +- Update win32/Makefile.gcc to build test/*.c [Truta] +- Permit stronger flushes after Z_BLOCK flushes +- Avoid extraneous empty blocks when doing empty flushes +- Permit Z_NULL arguments to deflatePending +- Allow deflatePrime() to insert bits in the middle of a stream +- Remove second empty static block for Z_PARTIAL_FLUSH +- Write out all of the available bits when using Z_BLOCK +- Insert the first two strings in the hash table after a flush + +Changes in 1.2.5.2 (17 Dec 2011) +- fix ld error: unable to find version dependency 'ZLIB_1.2.5' +- use relative symlinks for shared libs +- Avoid searching past window for Z_RLE strategy +- Assure that high-water mark initialization is always applied in deflate +- Add assertions to fill_window() in deflate.c to match comments +- Update python link in README +- Correct spelling error in gzread.c +- Fix bug in gzgets() for a concatenated empty gzip stream +- Correct error in comment for gz_make() +- Change gzread() and related to ignore junk after gzip streams +- Allow gzread() and related to continue after gzclearerr() +- Allow gzrewind() and gzseek() after a premature end-of-file +- Simplify gzseek() now that raw after gzip is ignored +- Change gzgetc() to a macro for speed (~40% speedup in testing) +- Fix gzclose() to return the actual error last encountered +- Always add large file support for windows +- Include zconf.h for windows large file support +- Include zconf.h.cmakein for windows large file support +- Update zconf.h.cmakein on make distclean +- Merge vestigial vsnprintf determination from zutil.h to gzguts.h +- Clarify how gzopen() appends in zlib.h comments +- Correct documentation of gzdirect() since junk at end now ignored +- Add a transparent write mode to gzopen() when 'T' is in the mode +- Update python link in zlib man page +- Get inffixed.h and MAKEFIXED result to match +- Add a ./config --solo option to make zlib subset with no libary use +- Add undocumented inflateResetKeep() function for CAB file decoding +- Add --cover option to ./configure for gcc coverage testing +- Add #define ZLIB_CONST option to use const in the z_stream interface +- Add comment to gzdopen() in zlib.h to use dup() when using fileno() +- Note behavior of uncompress() to provide as much data as it can +- Add files in contrib/minizip to aid in building libminizip +- Split off AR options in Makefile.in and configure +- Change ON macro to Z_ARG to avoid application conflicts +- Facilitate compilation with Borland C++ for pragmas and vsnprintf +- Include io.h for Turbo C / Borland C++ +- Move example.c and minigzip.c to test/ +- Simplify incomplete code table filling in inflate_table() +- Remove code from inflate.c and infback.c that is impossible to execute +- Test the inflate code with full coverage +- Allow deflateSetDictionary, inflateSetDictionary at any time (in raw) +- Add deflateResetKeep and fix inflateResetKeep to retain dictionary +- Fix gzwrite.c to accommodate reduced memory zlib compilation +- Have inflate() with Z_FINISH avoid the allocation of a window +- Do not set strm->adler when doing raw inflate +- Fix gzeof() to behave just like feof() when read is not past end of file +- Fix bug in gzread.c when end-of-file is reached +- Avoid use of Z_BUF_ERROR in gz* functions except for premature EOF +- Document gzread() capability to read concurrently written files +- Remove hard-coding of resource compiler in CMakeLists.txt [Blammo] + +Changes in 1.2.5.1 (10 Sep 2011) +- Update FAQ entry on shared builds (#13) +- Avoid symbolic argument to chmod in Makefile.in +- Fix bug and add consts in contrib/puff [Oberhumer] +- Update contrib/puff/zeros.raw test file to have all block types +- Add full coverage test for puff in contrib/puff/Makefile +- Fix static-only-build install in Makefile.in +- Fix bug in unzGetCurrentFileInfo() in contrib/minizip [Kuno] +- Add libz.a dependency to shared in Makefile.in for parallel builds +- Spell out "number" (instead of "nb") in zlib.h for total_in, total_out +- Replace $(...) with `...` in configure for non-bash sh [Bowler] +- Add darwin* to Darwin* and solaris* to SunOS\ 5* in configure [Groffen] +- Add solaris* to Linux* in configure to allow gcc use [Groffen] +- Add *bsd* to Linux* case in configure [Bar-Lev] +- Add inffast.obj to dependencies in win32/Makefile.msc +- Correct spelling error in deflate.h [Kohler] +- Change libzdll.a again to libz.dll.a (!) in win32/Makefile.gcc +- Add test to configure for GNU C looking for gcc in output of $cc -v +- Add zlib.pc generation to win32/Makefile.gcc [Weigelt] +- Fix bug in zlib.h for _FILE_OFFSET_BITS set and _LARGEFILE64_SOURCE not +- Add comment in zlib.h that adler32_combine with len2 < 0 makes no sense +- Make NO_DIVIDE option in adler32.c much faster (thanks to John Reiser) +- Make stronger test in zconf.h to include unistd.h for LFS +- Apply Darwin patches for 64-bit file offsets to contrib/minizip [Slack] +- Fix zlib.h LFS support when Z_PREFIX used +- Add updated as400 support (removed from old) [Monnerat] +- Avoid deflate sensitivity to volatile input data +- Avoid division in adler32_combine for NO_DIVIDE +- Clarify the use of Z_FINISH with deflateBound() amount of space +- Set binary for output file in puff.c +- Use u4 type for crc_table to avoid conversion warnings +- Apply casts in zlib.h to avoid conversion warnings +- Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller] +- Improve inflateSync() documentation to note indeterminancy +- Add deflatePending() function to return the amount of pending output +- Correct the spelling of "specification" in FAQ [Randers-Pehrson] +- Add a check in configure for stdarg.h, use for gzprintf() +- Check that pointers fit in ints when gzprint() compiled old style +- Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler] +- Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt] +- Add debug records in assmebler code [Londer] +- Update RFC references to use http://tools.ietf.org/html/... [Li] +- Add --archs option, use of libtool to configure for Mac OS X [Borstel] + +Changes in 1.2.5 (19 Apr 2010) +- Disable visibility attribute in win32/Makefile.gcc [Bar-Lev] +- Default to libdir as sharedlibdir in configure [Nieder] +- Update copyright dates on modified source files +- Update trees.c to be able to generate modified trees.h +- Exit configure for MinGW, suggesting win32/Makefile.gcc +- Check for NULL path in gz_open [Homurlu] + +Changes in 1.2.4.5 (18 Apr 2010) +- Set sharedlibdir in configure [Torok] +- Set LDFLAGS in Makefile.in [Bar-Lev] +- Avoid mkdir objs race condition in Makefile.in [Bowler] +- Add ZLIB_INTERNAL in front of internal inter-module functions and arrays +- Define ZLIB_INTERNAL to hide internal functions and arrays for GNU C +- Don't use hidden attribute when it is a warning generator (e.g. Solaris) + +Changes in 1.2.4.4 (18 Apr 2010) +- Fix CROSS_PREFIX executable testing, CHOST extract, mingw* [Torok] +- Undefine _LARGEFILE64_SOURCE in zconf.h if it is zero, but not if empty +- Try to use bash or ksh regardless of functionality of /bin/sh +- Fix configure incompatibility with NetBSD sh +- Remove attempt to run under bash or ksh since have better NetBSD fix +- Fix win32/Makefile.gcc for MinGW [Bar-Lev] +- Add diagnostic messages when using CROSS_PREFIX in configure +- Added --sharedlibdir option to configure [Weigelt] +- Use hidden visibility attribute when available [Frysinger] + +Changes in 1.2.4.3 (10 Apr 2010) +- Only use CROSS_PREFIX in configure for ar and ranlib if they exist +- Use CROSS_PREFIX for nm [Bar-Lev] +- Assume _LARGEFILE64_SOURCE defined is equivalent to true +- Avoid use of undefined symbols in #if with && and || +- Make *64 prototypes in gzguts.h consistent with functions +- Add -shared load option for MinGW in configure [Bowler] +- Move z_off64_t to public interface, use instead of off64_t +- Remove ! from shell test in configure (not portable to Solaris) +- Change +0 macro tests to -0 for possibly increased portability + +Changes in 1.2.4.2 (9 Apr 2010) +- Add consistent carriage returns to readme.txt's in masmx86 and masmx64 +- Really provide prototypes for *64 functions when building without LFS +- Only define unlink() in minigzip.c if unistd.h not included +- Update README to point to contrib/vstudio project files +- Move projects/vc6 to old/ and remove projects/ +- Include stdlib.h in minigzip.c for setmode() definition under WinCE +- Clean up assembler builds in win32/Makefile.msc [Rowe] +- Include sys/types.h for Microsoft for off_t definition +- Fix memory leak on error in gz_open() +- Symbolize nm as $NM in configure [Weigelt] +- Use TEST_LDSHARED instead of LDSHARED to link test programs [Weigelt] +- Add +0 to _FILE_OFFSET_BITS and _LFS64_LARGEFILE in case not defined +- Fix bug in gzeof() to take into account unused input data +- Avoid initialization of structures with variables in puff.c +- Updated win32/README-WIN32.txt [Rowe] + +Changes in 1.2.4.1 (28 Mar 2010) +- Remove the use of [a-z] constructs for sed in configure [gentoo 310225] +- Remove $(SHAREDLIB) from LIBS in Makefile.in [Creech] +- Restore "for debugging" comment on sprintf() in gzlib.c +- Remove fdopen for MVS from gzguts.h +- Put new README-WIN32.txt in win32 [Rowe] +- Add check for shell to configure and invoke another shell if needed +- Fix big fat stinking bug in gzseek() on uncompressed files +- Remove vestigial F_OPEN64 define in zutil.h +- Set and check the value of _LARGEFILE_SOURCE and _LARGEFILE64_SOURCE +- Avoid errors on non-LFS systems when applications define LFS macros +- Set EXE to ".exe" in configure for MINGW [Kahle] +- Match crc32() in crc32.c exactly to the prototype in zlib.h [Sherrill] +- Add prefix for cross-compilation in win32/makefile.gcc [Bar-Lev] +- Add DLL install in win32/makefile.gcc [Bar-Lev] +- Allow Linux* or linux* from uname in configure [Bar-Lev] +- Allow ldconfig to be redefined in configure and Makefile.in [Bar-Lev] +- Add cross-compilation prefixes to configure [Bar-Lev] +- Match type exactly in gz_load() invocation in gzread.c +- Match type exactly of zcalloc() in zutil.c to zlib.h alloc_func +- Provide prototypes for *64 functions when building zlib without LFS +- Don't use -lc when linking shared library on MinGW +- Remove errno.h check in configure and vestigial errno code in zutil.h + +Changes in 1.2.4 (14 Mar 2010) +- Fix VER3 extraction in configure for no fourth subversion +- Update zlib.3, add docs to Makefile.in to make .pdf out of it +- Add zlib.3.pdf to distribution +- Don't set error code in gzerror() if passed pointer is NULL +- Apply destination directory fixes to CMakeLists.txt [Lowman] +- Move #cmakedefine's to a new zconf.in.cmakein +- Restore zconf.h for builds that don't use configure or cmake +- Add distclean to dummy Makefile for convenience +- Update and improve INDEX, README, and FAQ +- Update CMakeLists.txt for the return of zconf.h [Lowman] +- Update contrib/vstudio/vc9 and vc10 [Vollant] +- Change libz.dll.a back to libzdll.a in win32/Makefile.gcc +- Apply license and readme changes to contrib/asm686 [Raiter] +- Check file name lengths and add -c option in minigzip.c [Li] +- Update contrib/amd64 and contrib/masmx86/ [Vollant] +- Avoid use of "eof" parameter in trees.c to not shadow library variable +- Update make_vms.com for removal of zlibdefs.h [Zinser] +- Update assembler code and vstudio projects in contrib [Vollant] +- Remove outdated assembler code contrib/masm686 and contrib/asm586 +- Remove old vc7 and vc8 from contrib/vstudio +- Update win32/Makefile.msc, add ZLIB_VER_SUBREVISION [Rowe] +- Fix memory leaks in gzclose_r() and gzclose_w(), file leak in gz_open() +- Add contrib/gcc_gvmat64 for longest_match and inflate_fast [Vollant] +- Remove *64 functions from win32/zlib.def (they're not 64-bit yet) +- Fix bug in void-returning vsprintf() case in gzwrite.c +- Fix name change from inflate.h in contrib/inflate86/inffas86.c +- Check if temporary file exists before removing in make_vms.com [Zinser] +- Fix make install and uninstall for --static option +- Fix usage of _MSC_VER in gzguts.h and zutil.h [Truta] +- Update readme.txt in contrib/masmx64 and masmx86 to assemble + +Changes in 1.2.3.9 (21 Feb 2010) +- Expunge gzio.c +- Move as400 build information to old +- Fix updates in contrib/minizip and contrib/vstudio +- Add const to vsnprintf test in configure to avoid warnings [Weigelt] +- Delete zconf.h (made by configure) [Weigelt] +- Change zconf.in.h to zconf.h.in per convention [Weigelt] +- Check for NULL buf in gzgets() +- Return empty string for gzgets() with len == 1 (like fgets()) +- Fix description of gzgets() in zlib.h for end-of-file, NULL return +- Update minizip to 1.1 [Vollant] +- Avoid MSVC loss of data warnings in gzread.c, gzwrite.c +- Note in zlib.h that gzerror() should be used to distinguish from EOF +- Remove use of snprintf() from gzlib.c +- Fix bug in gzseek() +- Update contrib/vstudio, adding vc9 and vc10 [Kuno, Vollant] +- Fix zconf.h generation in CMakeLists.txt [Lowman] +- Improve comments in zconf.h where modified by configure + +Changes in 1.2.3.8 (13 Feb 2010) +- Clean up text files (tabs, trailing whitespace, etc.) [Oberhumer] +- Use z_off64_t in gz_zero() and gz_skip() to match state->skip +- Avoid comparison problem when sizeof(int) == sizeof(z_off64_t) +- Revert to Makefile.in from 1.2.3.6 (live with the clutter) +- Fix missing error return in gzflush(), add zlib.h note +- Add *64 functions to zlib.map [Levin] +- Fix signed/unsigned comparison in gz_comp() +- Use SFLAGS when testing shared linking in configure +- Add --64 option to ./configure to use -m64 with gcc +- Fix ./configure --help to correctly name options +- Have make fail if a test fails [Levin] +- Avoid buffer overrun in contrib/masmx64/gvmat64.asm [Simpson] +- Remove assembler object files from contrib + +Changes in 1.2.3.7 (24 Jan 2010) +- Always gzopen() with O_LARGEFILE if available +- Fix gzdirect() to work immediately after gzopen() or gzdopen() +- Make gzdirect() more precise when the state changes while reading +- Improve zlib.h documentation in many places +- Catch memory allocation failure in gz_open() +- Complete close operation if seek forward in gzclose_w() fails +- Return Z_ERRNO from gzclose_r() if close() fails +- Return Z_STREAM_ERROR instead of EOF for gzclose() being passed NULL +- Return zero for gzwrite() errors to match zlib.h description +- Return -1 on gzputs() error to match zlib.h description +- Add zconf.in.h to allow recovery from configure modification [Weigelt] +- Fix static library permissions in Makefile.in [Weigelt] +- Avoid warnings in configure tests that hide functionality [Weigelt] +- Add *BSD and DragonFly to Linux case in configure [gentoo 123571] +- Change libzdll.a to libz.dll.a in win32/Makefile.gcc [gentoo 288212] +- Avoid access of uninitialized data for first inflateReset2 call [Gomes] +- Keep object files in subdirectories to reduce the clutter somewhat +- Remove default Makefile and zlibdefs.h, add dummy Makefile +- Add new external functions to Z_PREFIX, remove duplicates, z_z_ -> z_ +- Remove zlibdefs.h completely -- modify zconf.h instead + +Changes in 1.2.3.6 (17 Jan 2010) +- Avoid void * arithmetic in gzread.c and gzwrite.c +- Make compilers happier with const char * for gz_error message +- Avoid unused parameter warning in inflate.c +- Avoid signed-unsigned comparison warning in inflate.c +- Indent #pragma's for traditional C +- Fix usage of strwinerror() in glib.c, change to gz_strwinerror() +- Correct email address in configure for system options +- Update make_vms.com and add make_vms.com to contrib/minizip [Zinser] +- Update zlib.map [Brown] +- Fix Makefile.in for Solaris 10 make of example64 and minizip64 [Torok] +- Apply various fixes to CMakeLists.txt [Lowman] +- Add checks on len in gzread() and gzwrite() +- Add error message for no more room for gzungetc() +- Remove zlib version check in gzwrite() +- Defer compression of gzprintf() result until need to +- Use snprintf() in gzdopen() if available +- Remove USE_MMAP configuration determination (only used by minigzip) +- Remove examples/pigz.c (available separately) +- Update examples/gun.c to 1.6 + +Changes in 1.2.3.5 (8 Jan 2010) +- Add space after #if in zutil.h for some compilers +- Fix relatively harmless bug in deflate_fast() [Exarevsky] +- Fix same problem in deflate_slow() +- Add $(SHAREDLIBV) to LIBS in Makefile.in [Brown] +- Add deflate_rle() for faster Z_RLE strategy run-length encoding +- Add deflate_huff() for faster Z_HUFFMAN_ONLY encoding +- Change name of "write" variable in inffast.c to avoid library collisions +- Fix premature EOF from gzread() in gzio.c [Brown] +- Use zlib header window size if windowBits is 0 in inflateInit2() +- Remove compressBound() call in deflate.c to avoid linking compress.o +- Replace use of errno in gz* with functions, support WinCE [Alves] +- Provide alternative to perror() in minigzip.c for WinCE [Alves] +- Don't use _vsnprintf on later versions of MSVC [Lowman] +- Add CMake build script and input file [Lowman] +- Update contrib/minizip to 1.1 [Svensson, Vollant] +- Moved nintendods directory from contrib to . +- Replace gzio.c with a new set of routines with the same functionality +- Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above +- Update contrib/minizip to 1.1b +- Change gzeof() to return 0 on error instead of -1 to agree with zlib.h + +Changes in 1.2.3.4 (21 Dec 2009) +- Use old school .SUFFIXES in Makefile.in for FreeBSD compatibility +- Update comments in configure and Makefile.in for default --shared +- Fix test -z's in configure [Marquess] +- Build examplesh and minigzipsh when not testing +- Change NULL's to Z_NULL's in deflate.c and in comments in zlib.h +- Import LDFLAGS from the environment in configure +- Fix configure to populate SFLAGS with discovered CFLAGS options +- Adapt make_vms.com to the new Makefile.in [Zinser] +- Add zlib2ansi script for C++ compilation [Marquess] +- Add _FILE_OFFSET_BITS=64 test to make test (when applicable) +- Add AMD64 assembler code for longest match to contrib [Teterin] +- Include options from $SFLAGS when doing $LDSHARED +- Simplify 64-bit file support by introducing z_off64_t type +- Make shared object files in objs directory to work around old Sun cc +- Use only three-part version number for Darwin shared compiles +- Add rc option to ar in Makefile.in for when ./configure not run +- Add -WI,-rpath,. to LDFLAGS for OSF 1 V4* +- Set LD_LIBRARYN32_PATH for SGI IRIX shared compile +- Protect against _FILE_OFFSET_BITS being defined when compiling zlib +- Rename Makefile.in targets allstatic to static and allshared to shared +- Fix static and shared Makefile.in targets to be independent +- Correct error return bug in gz_open() by setting state [Brown] +- Put spaces before ;;'s in configure for better sh compatibility +- Add pigz.c (parallel implementation of gzip) to examples/ +- Correct constant in crc32.c to UL [Leventhal] +- Reject negative lengths in crc32_combine() +- Add inflateReset2() function to work like inflateEnd()/inflateInit2() +- Include sys/types.h for _LARGEFILE64_SOURCE [Brown] +- Correct typo in doc/algorithm.txt [Janik] +- Fix bug in adler32_combine() [Zhu] +- Catch missing-end-of-block-code error in all inflates and in puff + Assures that random input to inflate eventually results in an error +- Added enough.c (calculation of ENOUGH for inftrees.h) to examples/ +- Update ENOUGH and its usage to reflect discovered bounds +- Fix gzerror() error report on empty input file [Brown] +- Add ush casts in trees.c to avoid pedantic runtime errors +- Fix typo in zlib.h uncompress() description [Reiss] +- Correct inflate() comments with regard to automatic header detection +- Remove deprecation comment on Z_PARTIAL_FLUSH (it stays) +- Put new version of gzlog (2.0) in examples with interruption recovery +- Add puff compile option to permit invalid distance-too-far streams +- Add puff TEST command options, ability to read piped input +- Prototype the *64 functions in zlib.h when _FILE_OFFSET_BITS == 64, but + _LARGEFILE64_SOURCE not defined +- Fix Z_FULL_FLUSH to truly erase the past by resetting s->strstart +- Fix deflateSetDictionary() to use all 32K for output consistency +- Remove extraneous #define MIN_LOOKAHEAD in deflate.c (in deflate.h) +- Clear bytes after deflate lookahead to avoid use of uninitialized data +- Change a limit in inftrees.c to be more transparent to Coverity Prevent +- Update win32/zlib.def with exported symbols from zlib.h +- Correct spelling errors in zlib.h [Willem, Sobrado] +- Allow Z_BLOCK for deflate() to force a new block +- Allow negative bits in inflatePrime() to delete existing bit buffer +- Add Z_TREES flush option to inflate() to return at end of trees +- Add inflateMark() to return current state information for random access +- Add Makefile for NintendoDS to contrib [Costa] +- Add -w in configure compile tests to avoid spurious warnings [Beucler] +- Fix typos in zlib.h comments for deflateSetDictionary() +- Fix EOF detection in transparent gzread() [Maier] + +Changes in 1.2.3.3 (2 October 2006) +- Make --shared the default for configure, add a --static option +- Add compile option to permit invalid distance-too-far streams +- Add inflateUndermine() function which is required to enable above +- Remove use of "this" variable name for C++ compatibility [Marquess] +- Add testing of shared library in make test, if shared library built +- Use ftello() and fseeko() if available instead of ftell() and fseek() +- Provide two versions of all functions that use the z_off_t type for + binary compatibility -- a normal version and a 64-bit offset version, + per the Large File Support Extension when _LARGEFILE64_SOURCE is + defined; use the 64-bit versions by default when _FILE_OFFSET_BITS + is defined to be 64 +- Add a --uname= option to configure to perhaps help with cross-compiling + +Changes in 1.2.3.2 (3 September 2006) +- Turn off silly Borland warnings [Hay] +- Use off64_t and define _LARGEFILE64_SOURCE when present +- Fix missing dependency on inffixed.h in Makefile.in +- Rig configure --shared to build both shared and static [Teredesai, Truta] +- Remove zconf.in.h and instead create a new zlibdefs.h file +- Fix contrib/minizip/unzip.c non-encrypted after encrypted [Vollant] +- Add treebuild.xml (see http://treebuild.metux.de/) [Weigelt] + +Changes in 1.2.3.1 (16 August 2006) +- Add watcom directory with OpenWatcom make files [Daniel] +- Remove #undef of FAR in zconf.in.h for MVS [Fedtke] +- Update make_vms.com [Zinser] +- Use -fPIC for shared build in configure [Teredesai, Nicholson] +- Use only major version number for libz.so on IRIX and OSF1 [Reinholdtsen] +- Use fdopen() (not _fdopen()) for Interix in zutil.h [BŠck] +- Add some FAQ entries about the contrib directory +- Update the MVS question in the FAQ +- Avoid extraneous reads after EOF in gzio.c [Brown] +- Correct spelling of "successfully" in gzio.c [Randers-Pehrson] +- Add comments to zlib.h about gzerror() usage [Brown] +- Set extra flags in gzip header in gzopen() like deflate() does +- Make configure options more compatible with double-dash conventions + [Weigelt] +- Clean up compilation under Solaris SunStudio cc [Rowe, Reinholdtsen] +- Fix uninstall target in Makefile.in [Truta] +- Add pkgconfig support [Weigelt] +- Use $(DESTDIR) macro in Makefile.in [Reinholdtsen, Weigelt] +- Replace set_data_type() with a more accurate detect_data_type() in + trees.c, according to the txtvsbin.txt document [Truta] +- Swap the order of #include and #include "zlib.h" in + gzio.c, example.c and minigzip.c [Truta] +- Shut up annoying VS2005 warnings about standard C deprecation [Rowe, + Truta] (where?) +- Fix target "clean" from win32/Makefile.bor [Truta] +- Create .pdb and .manifest files in win32/makefile.msc [Ziegler, Rowe] +- Update zlib www home address in win32/DLL_FAQ.txt [Truta] +- Update contrib/masmx86/inffas32.asm for VS2005 [Vollant, Van Wassenhove] +- Enable browse info in the "Debug" and "ASM Debug" configurations in + the Visual C++ 6 project, and set (non-ASM) "Debug" as default [Truta] +- Add pkgconfig support [Weigelt] +- Add ZLIB_VER_MAJOR, ZLIB_VER_MINOR and ZLIB_VER_REVISION in zlib.h, + for use in win32/zlib1.rc [Polushin, Rowe, Truta] +- Add a document that explains the new text detection scheme to + doc/txtvsbin.txt [Truta] +- Add rfc1950.txt, rfc1951.txt and rfc1952.txt to doc/ [Truta] +- Move algorithm.txt into doc/ [Truta] +- Synchronize FAQ with website +- Fix compressBound(), was low for some pathological cases [Fearnley] +- Take into account wrapper variations in deflateBound() +- Set examples/zpipe.c input and output to binary mode for Windows +- Update examples/zlib_how.html with new zpipe.c (also web site) +- Fix some warnings in examples/gzlog.c and examples/zran.c (it seems + that gcc became pickier in 4.0) +- Add zlib.map for Linux: "All symbols from zlib-1.1.4 remain + un-versioned, the patch adds versioning only for symbols introduced in + zlib-1.2.0 or later. It also declares as local those symbols which are + not designed to be exported." [Levin] +- Update Z_PREFIX list in zconf.in.h, add --zprefix option to configure +- Do not initialize global static by default in trees.c, add a response + NO_INIT_GLOBAL_POINTERS to initialize them if needed [Marquess] +- Don't use strerror() in gzio.c under WinCE [Yakimov] +- Don't use errno.h in zutil.h under WinCE [Yakimov] +- Move arguments for AR to its usage to allow replacing ar [Marot] +- Add HAVE_VISIBILITY_PRAGMA in zconf.in.h for Mozilla [Randers-Pehrson] +- Improve inflateInit() and inflateInit2() documentation +- Fix structure size comment in inflate.h +- Change configure help option from --h* to --help [Santos] + +Changes in 1.2.3 (18 July 2005) +- Apply security vulnerability fixes to contrib/infback9 as well +- Clean up some text files (carriage returns, trailing space) +- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant] + +Changes in 1.2.2.4 (11 July 2005) +- Add inflatePrime() function for starting inflation at bit boundary +- Avoid some Visual C warnings in deflate.c +- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit + compile +- Fix some spelling errors in comments [Betts] +- Correct inflateInit2() error return documentation in zlib.h +- Add zran.c example of compressed data random access to examples + directory, shows use of inflatePrime() +- Fix cast for assignments to strm->state in inflate.c and infback.c +- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer] +- Move declarations of gf2 functions to right place in crc32.c [Oberhumer] +- Add cast in trees.c t avoid a warning [Oberhumer] +- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer] +- Update make_vms.com [Zinser] +- Initialize state->write in inflateReset() since copied in inflate_fast() +- Be more strict on incomplete code sets in inflate_table() and increase + ENOUGH and MAXD -- this repairs a possible security vulnerability for + invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for + discovering the vulnerability and providing test cases. +- Add ia64 support to configure for HP-UX [Smith] +- Add error return to gzread() for format or i/o error [Levin] +- Use malloc.h for OS/2 [Necasek] + +Changes in 1.2.2.3 (27 May 2005) +- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile +- Typecast fread() return values in gzio.c [Vollant] +- Remove trailing space in minigzip.c outmode (VC++ can't deal with it) +- Fix crc check bug in gzread() after gzungetc() [Heiner] +- Add the deflateTune() function to adjust internal compression parameters +- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack) +- Remove an incorrect assertion in examples/zpipe.c +- Add C++ wrapper in infback9.h [Donais] +- Fix bug in inflateCopy() when decoding fixed codes +- Note in zlib.h how much deflateSetDictionary() actually uses +- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used) +- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer] +- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer] +- Add gzdirect() function to indicate transparent reads +- Update contrib/minizip [Vollant] +- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer] +- Add casts in crc32.c to avoid warnings [Oberhumer] +- Add contrib/masmx64 [Vollant] +- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant] + +Changes in 1.2.2.2 (30 December 2004) +- Replace structure assignments in deflate.c and inflate.c with zmemcpy to + avoid implicit memcpy calls (portability for no-library compilation) +- Increase sprintf() buffer size in gzdopen() to allow for large numbers +- Add INFLATE_STRICT to check distances against zlib header +- Improve WinCE errno handling and comments [Chang] +- Remove comment about no gzip header processing in FAQ +- Add Z_FIXED strategy option to deflateInit2() to force fixed trees +- Add updated make_vms.com [Coghlan], update README +- Create a new "examples" directory, move gzappend.c there, add zpipe.c, + fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html. +- Add FAQ entry and comments in deflate.c on uninitialized memory access +- Add Solaris 9 make options in configure [Gilbert] +- Allow strerror() usage in gzio.c for STDC +- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer] +- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant] +- Use z_off_t for adler32_combine() and crc32_combine() lengths +- Make adler32() much faster for small len +- Use OS_CODE in deflate() default gzip header + +Changes in 1.2.2.1 (31 October 2004) +- Allow inflateSetDictionary() call for raw inflate +- Fix inflate header crc check bug for file names and comments +- Add deflateSetHeader() and gz_header structure for custom gzip headers +- Add inflateGetheader() to retrieve gzip headers +- Add crc32_combine() and adler32_combine() functions +- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list +- Use zstreamp consistently in zlib.h (inflate_back functions) +- Remove GUNZIP condition from definition of inflate_mode in inflate.h + and in contrib/inflate86/inffast.S [Truta, Anderson] +- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson] +- Update projects/README.projects and projects/visualc6 [Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta] +- Deprecate Z_ASCII; use Z_TEXT instead [Truta] +- Use a new algorithm for setting strm->data_type in trees.c [Truta] +- Do not define an exit() prototype in zutil.c unless DEBUG defined +- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta] +- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate() +- Fix Darwin build version identification [Peterson] + +Changes in 1.2.2 (3 October 2004) +- Update zlib.h comments on gzip in-memory processing +- Set adler to 1 in inflateReset() to support Java test suite [Walles] +- Add contrib/dotzlib [Ravn] +- Update win32/DLL_FAQ.txt [Truta] +- Update contrib/minizip [Vollant] +- Move contrib/visual-basic.txt to old/ [Truta] +- Fix assembler builds in projects/visualc6/ [Truta] + +Changes in 1.2.1.2 (9 September 2004) +- Update INDEX file +- Fix trees.c to update strm->data_type (no one ever noticed!) +- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown] +- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE) +- Add limited multitasking protection to DYNAMIC_CRC_TABLE +- Add NO_vsnprintf for VMS in zutil.h [Mozilla] +- Don't declare strerror() under VMS [Mozilla] +- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize +- Update contrib/ada [Anisimkov] +- Update contrib/minizip [Vollant] +- Fix configure to not hardcode directories for Darwin [Peterson] +- Fix gzio.c to not return error on empty files [Brown] +- Fix indentation; update version in contrib/delphi/ZLib.pas and + contrib/pascal/zlibpas.pas [Truta] +- Update mkasm.bat in contrib/masmx86 [Truta] +- Update contrib/untgz [Truta] +- Add projects/README.projects [Truta] +- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta] +- Update win32/DLL_FAQ.txt [Truta] +- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta] +- Remove an unnecessary assignment to curr in inftrees.c [Truta] +- Add OS/2 to exe builds in configure [Poltorak] +- Remove err dummy parameter in zlib.h [Kientzle] + +Changes in 1.2.1.1 (9 January 2004) +- Update email address in README +- Several FAQ updates +- Fix a big fat bug in inftrees.c that prevented decoding valid + dynamic blocks with only literals and no distance codes -- + Thanks to "Hot Emu" for the bug report and sample file +- Add a note to puff.c on no distance codes case. + +Changes in 1.2.1 (17 November 2003) +- Remove a tab in contrib/gzappend/gzappend.c +- Update some interfaces in contrib for new zlib functions +- Update zlib version number in some contrib entries +- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta] +- Support shared libraries on Hurd and KFreeBSD [Brown] +- Fix error in NO_DIVIDE option of adler32.c + +Changes in 1.2.0.8 (4 November 2003) +- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas +- Add experimental NO_DIVIDE #define in adler32.c + - Possibly faster on some processors (let me know if it is) +- Correct Z_BLOCK to not return on first inflate call if no wrap +- Fix strm->data_type on inflate() return to correctly indicate EOB +- Add deflatePrime() function for appending in the middle of a byte +- Add contrib/gzappend for an example of appending to a stream +- Update win32/DLL_FAQ.txt [Truta] +- Delete Turbo C comment in README [Truta] +- Improve some indentation in zconf.h [Truta] +- Fix infinite loop on bad input in configure script [Church] +- Fix gzeof() for concatenated gzip files [Johnson] +- Add example to contrib/visual-basic.txt [Michael B.] +- Add -p to mkdir's in Makefile.in [vda] +- Fix configure to properly detect presence or lack of printf functions +- Add AS400 support [Monnerat] +- Add a little Cygwin support [Wilson] + +Changes in 1.2.0.7 (21 September 2003) +- Correct some debug formats in contrib/infback9 +- Cast a type in a debug statement in trees.c +- Change search and replace delimiter in configure from % to # [Beebe] +- Update contrib/untgz to 0.2 with various fixes [Truta] +- Add build support for Amiga [Nikl] +- Remove some directories in old that have been updated to 1.2 +- Add dylib building for Mac OS X in configure and Makefile.in +- Remove old distribution stuff from Makefile +- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X +- Update links in README + +Changes in 1.2.0.6 (13 September 2003) +- Minor FAQ updates +- Update contrib/minizip to 1.00 [Vollant] +- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta] +- Update POSTINC comment for 68060 [Nikl] +- Add contrib/infback9 with deflate64 decoding (unsupported) +- For MVS define NO_vsnprintf and undefine FAR [van Burik] +- Add pragma for fdopen on MVS [van Burik] + +Changes in 1.2.0.5 (8 September 2003) +- Add OF to inflateBackEnd() declaration in zlib.h +- Remember start when using gzdopen in the middle of a file +- Use internal off_t counters in gz* functions to properly handle seeks +- Perform more rigorous check for distance-too-far in inffast.c +- Add Z_BLOCK flush option to return from inflate at block boundary +- Set strm->data_type on return from inflate + - Indicate bits unused, if at block boundary, and if in last block +- Replace size_t with ptrdiff_t in crc32.c, and check for correct size +- Add condition so old NO_DEFLATE define still works for compatibility +- FAQ update regarding the Windows DLL [Truta] +- INDEX update: add qnx entry, remove aix entry [Truta] +- Install zlib.3 into mandir [Wilson] +- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta] +- Adapt the zlib interface to the new DLL convention guidelines [Truta] +- Introduce ZLIB_WINAPI macro to allow the export of functions using + the WINAPI calling convention, for Visual Basic [Vollant, Truta] +- Update msdos and win32 scripts and makefiles [Truta] +- Export symbols by name, not by ordinal, in win32/zlib.def [Truta] +- Add contrib/ada [Anisimkov] +- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta] +- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant] +- Add contrib/masm686 [Truta] +- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm + [Truta, Vollant] +- Update contrib/delphi; rename to contrib/pascal; add example [Truta] +- Remove contrib/delphi2; add a new contrib/delphi [Truta] +- Avoid inclusion of the nonstandard in contrib/iostream, + and fix some method prototypes [Truta] +- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip + [Truta] +- Avoid the use of backslash (\) in contrib/minizip [Vollant] +- Fix file time handling in contrib/untgz; update makefiles [Truta] +- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines + [Vollant] +- Remove contrib/vstudio/vc15_16 [Vollant] +- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta] +- Update README.contrib [Truta] +- Invert the assignment order of match_head and s->prev[...] in + INSERT_STRING [Truta] +- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings + [Truta] +- Compare function pointers with 0, not with NULL or Z_NULL [Truta] +- Fix prototype of syncsearch in inflate.c [Truta] +- Introduce ASMINF macro to be enabled when using an ASM implementation + of inflate_fast [Truta] +- Change NO_DEFLATE to NO_GZCOMPRESS [Truta] +- Modify test_gzio in example.c to take a single file name as a + parameter [Truta] +- Exit the example.c program if gzopen fails [Truta] +- Add type casts around strlen in example.c [Truta] +- Remove casting to sizeof in minigzip.c; give a proper type + to the variable compared with SUFFIX_LEN [Truta] +- Update definitions of STDC and STDC99 in zconf.h [Truta] +- Synchronize zconf.h with the new Windows DLL interface [Truta] +- Use SYS16BIT instead of __32BIT__ to distinguish between + 16- and 32-bit platforms [Truta] +- Use far memory allocators in small 16-bit memory models for + Turbo C [Truta] +- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in + zlibCompileFlags [Truta] +- Cygwin has vsnprintf [Wilson] +- In Windows16, OS_CODE is 0, as in MSDOS [Truta] +- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson] + +Changes in 1.2.0.4 (10 August 2003) +- Minor FAQ updates +- Be more strict when checking inflateInit2's windowBits parameter +- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well +- Add gzip wrapper option to deflateInit2 using windowBits +- Add updated QNX rule in configure and qnx directory [Bonnefoy] +- Make inflate distance-too-far checks more rigorous +- Clean up FAR usage in inflate +- Add casting to sizeof() in gzio.c and minigzip.c + +Changes in 1.2.0.3 (19 July 2003) +- Fix silly error in gzungetc() implementation [Vollant] +- Update contrib/minizip and contrib/vstudio [Vollant] +- Fix printf format in example.c +- Correct cdecl support in zconf.in.h [Anisimkov] +- Minor FAQ updates + +Changes in 1.2.0.2 (13 July 2003) +- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons +- Attempt to avoid warnings in crc32.c for pointer-int conversion +- Add AIX to configure, remove aix directory [Bakker] +- Add some casts to minigzip.c +- Improve checking after insecure sprintf() or vsprintf() calls +- Remove #elif's from crc32.c +- Change leave label to inf_leave in inflate.c and infback.c to avoid + library conflicts +- Remove inflate gzip decoding by default--only enable gzip decoding by + special request for stricter backward compatibility +- Add zlibCompileFlags() function to return compilation information +- More typecasting in deflate.c to avoid warnings +- Remove leading underscore from _Capital #defines [Truta] +- Fix configure to link shared library when testing +- Add some Windows CE target adjustments [Mai] +- Remove #define ZLIB_DLL in zconf.h [Vollant] +- Add zlib.3 [Rodgers] +- Update RFC URL in deflate.c and algorithm.txt [Mai] +- Add zlib_dll_FAQ.txt to contrib [Truta] +- Add UL to some constants [Truta] +- Update minizip and vstudio [Vollant] +- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h +- Expand use of NO_DUMMY_DECL to avoid all dummy structures +- Added iostream3 to contrib [Schwardt] +- Replace rewind() with fseek() for WinCE [Truta] +- Improve setting of zlib format compression level flags + - Report 0 for huffman and rle strategies and for level == 0 or 1 + - Report 2 only for level == 6 +- Only deal with 64K limit when necessary at compile time [Truta] +- Allow TOO_FAR check to be turned off at compile time [Truta] +- Add gzclearerr() function [Souza] +- Add gzungetc() function + +Changes in 1.2.0.1 (17 March 2003) +- Add Z_RLE strategy for run-length encoding [Truta] + - When Z_RLE requested, restrict matches to distance one + - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE +- Correct FASTEST compilation to allow level == 0 +- Clean up what gets compiled for FASTEST +- Incorporate changes to zconf.in.h [Vollant] + - Refine detection of Turbo C need for dummy returns + - Refine ZLIB_DLL compilation + - Include additional header file on VMS for off_t typedef +- Try to use _vsnprintf where it supplants vsprintf [Vollant] +- Add some casts in inffast.c +- Enchance comments in zlib.h on what happens if gzprintf() tries to + write more than 4095 bytes before compression +- Remove unused state from inflateBackEnd() +- Remove exit(0) from minigzip.c, example.c +- Get rid of all those darn tabs +- Add "check" target to Makefile.in that does the same thing as "test" +- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in +- Update contrib/inflate86 [Anderson] +- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant] +- Add msdos and win32 directories with makefiles [Truta] +- More additions and improvements to the FAQ + +Changes in 1.2.0 (9 March 2003) +- New and improved inflate code + - About 20% faster + - Does not allocate 32K window unless and until needed + - Automatically detects and decompresses gzip streams + - Raw inflate no longer needs an extra dummy byte at end + - Added inflateBack functions using a callback interface--even faster + than inflate, useful for file utilities (gzip, zip) + - Added inflateCopy() function to record state for random access on + externally generated deflate streams (e.g. in gzip files) + - More readable code (I hope) +- New and improved crc32() + - About 50% faster, thanks to suggestions from Rodney Brown +- Add deflateBound() and compressBound() functions +- Fix memory leak in deflateInit2() +- Permit setting dictionary for raw deflate (for parallel deflate) +- Fix const declaration for gzwrite() +- Check for some malloc() failures in gzio.c +- Fix bug in gzopen() on single-byte file 0x1f +- Fix bug in gzread() on concatenated file with 0x1f at end of buffer + and next buffer doesn't start with 0x8b +- Fix uncompress() to return Z_DATA_ERROR on truncated input +- Free memory at end of example.c +- Remove MAX #define in trees.c (conflicted with some libraries) +- Fix static const's in deflate.c, gzio.c, and zutil.[ch] +- Declare malloc() and free() in gzio.c if STDC not defined +- Use malloc() instead of calloc() in zutil.c if int big enough +- Define STDC for AIX +- Add aix/ with approach for compiling shared library on AIX +- Add HP-UX support for shared libraries in configure +- Add OpenUNIX support for shared libraries in configure +- Use $cc instead of gcc to build shared library +- Make prefix directory if needed when installing +- Correct Macintosh avoidance of typedef Byte in zconf.h +- Correct Turbo C memory allocation when under Linux +- Use libz.a instead of -lz in Makefile (assure use of compiled library) +- Update configure to check for snprintf or vsnprintf functions and their + return value, warn during make if using an insecure function +- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that + is lost when library is used--resolution is to build new zconf.h +- Documentation improvements (in zlib.h): + - Document raw deflate and inflate + - Update RFCs URL + - Point out that zlib and gzip formats are different + - Note that Z_BUF_ERROR is not fatal + - Document string limit for gzprintf() and possible buffer overflow + - Note requirement on avail_out when flushing + - Note permitted values of flush parameter of inflate() +- Add some FAQs (and even answers) to the FAQ +- Add contrib/inflate86/ for x86 faster inflate +- Add contrib/blast/ for PKWare Data Compression Library decompression +- Add contrib/puff/ simple inflate for deflate format description + +Changes in 1.1.4 (11 March 2002) +- ZFREE was repeated on same allocation on some error conditions. + This creates a security problem described in + http://www.zlib.org/advisory-2002-03-11.txt +- Returned incorrect error (Z_MEM_ERROR) on some invalid data +- Avoid accesses before window for invalid distances with inflate window + less than 32K. +- force windowBits > 8 to avoid a bug in the encoder for a window size + of 256 bytes. (A complete fix will be available in 1.1.5). + +Changes in 1.1.3 (9 July 1998) +- fix "an inflate input buffer bug that shows up on rare but persistent + occasions" (Mark) +- fix gzread and gztell for concatenated .gz files (Didier Le Botlan) +- fix gzseek(..., SEEK_SET) in write mode +- fix crc check after a gzeek (Frank Faubert) +- fix miniunzip when the last entry in a zip file is itself a zip file + (J Lillge) +- add contrib/asm586 and contrib/asm686 (Brian Raiter) + See http://www.muppetlabs.com/~breadbox/software/assembly.html +- add support for Delphi 3 in contrib/delphi (Bob Dellaca) +- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti) +- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren) +- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks) +- added a FAQ file + +- Support gzdopen on Mac with Metrowerks (Jason Linhart) +- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart) +- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young) +- avoid some warnings with Borland C (Tom Tanner) +- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant) +- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant) +- allow several arguments to configure (Tim Mooney, Frodo Looijaard) +- use libdir and includedir in Makefile.in (Tim Mooney) +- support shared libraries on OSF1 V4 (Tim Mooney) +- remove so_locations in "make clean" (Tim Mooney) +- fix maketree.c compilation error (Glenn, Mark) +- Python interface to zlib now in Python 1.5 (Jeremy Hylton) +- new Makefile.riscos (Rich Walker) +- initialize static descriptors in trees.c for embedded targets (Nick Smith) +- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith) +- add the OS/2 files in Makefile.in too (Andrew Zabolotny) +- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane) +- fix maketree.c to allow clean compilation of inffixed.h (Mark) +- fix parameter check in deflateCopy (Gunther Nikl) +- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler) +- Many portability patches by Christian Spieler: + . zutil.c, zutil.h: added "const" for zmem* + . Make_vms.com: fixed some typos + . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists + . msdos/Makefile.msc: remove "default rtl link library" info from obj files + . msdos/Makefile.*: use model-dependent name for the built zlib library + . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc: + new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT) +- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane) +- replace __far with _far for better portability (Christian Spieler, Tom Lane) +- fix test for errno.h in configure (Tim Newsham) + +Changes in 1.1.2 (19 March 98) +- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant) + See http://www.winimage.com/zLibDll/unzip.html +- preinitialize the inflate tables for fixed codes, to make the code + completely thread safe (Mark) +- some simplifications and slight speed-up to the inflate code (Mark) +- fix gzeof on non-compressed files (Allan Schrum) +- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs) +- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn) +- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny) +- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori) +- do not wrap extern "C" around system includes (Tom Lane) +- mention zlib binding for TCL in README (Andreas Kupries) +- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert) +- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson) +- allow "configure --prefix $HOME" (Tim Mooney) +- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson) +- move Makefile.sas to amiga/Makefile.sas + +Changes in 1.1.1 (27 Feb 98) +- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson) +- remove block truncation heuristic which had very marginal effect for zlib + (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the + compression ratio on some files. This also allows inlining _tr_tally for + matches in deflate_slow. +- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier) + +Changes in 1.1.0 (24 Feb 98) +- do not return STREAM_END prematurely in inflate (John Bowler) +- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler) +- compile with -DFASTEST to get compression code optimized for speed only +- in minigzip, try mmap'ing the input file first (Miguel Albrecht) +- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain + on Sun but significant on HP) + +- add a pointer to experimental unzip library in README (Gilles Vollant) +- initialize variable gcc in configure (Chris Herborth) + +Changes in 1.0.9 (17 Feb 1998) +- added gzputs and gzgets functions +- do not clear eof flag in gzseek (Mark Diekhans) +- fix gzseek for files in transparent mode (Mark Diekhans) +- do not assume that vsprintf returns the number of bytes written (Jens Krinke) +- replace EXPORT with ZEXPORT to avoid conflict with other programs +- added compress2 in zconf.h, zlib.def, zlib.dnt +- new asm code from Gilles Vollant in contrib/asm386 +- simplify the inflate code (Mark): + . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new() + . ZALLOC the length list in inflate_trees_fixed() instead of using stack + . ZALLOC the value area for huft_build() instead of using stack + . Simplify Z_FINISH check in inflate() + +- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8 +- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi) +- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with + the declaration of FAR (Gilles VOllant) +- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann) +- read_buf buf parameter of type Bytef* instead of charf* +- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout) +- do not redeclare unlink in minigzip.c for WIN32 (John Bowler) +- fix check for presence of directories in "make install" (Ian Willis) + +Changes in 1.0.8 (27 Jan 1998) +- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant) +- fix gzgetc and gzputc for big endian systems (Markus Oberhumer) +- added compress2() to allow setting the compression level +- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong) +- use constant arrays for the static trees in trees.c instead of computing + them at run time (thanks to Ken Raeburn for this suggestion). To create + trees.h, compile with GEN_TREES_H and run "make test". +- check return code of example in "make test" and display result +- pass minigzip command line options to file_compress +- simplifying code of inflateSync to avoid gcc 2.8 bug + +- support CC="gcc -Wall" in configure -s (QingLong) +- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn) +- fix test for shared library support to avoid compiler warnings +- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant) +- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit) +- do not use fdopen for Metrowerks on Mac (Brad Pettit)) +- add checks for gzputc and gzputc in example.c +- avoid warnings in gzio.c and deflate.c (Andreas Kleinert) +- use const for the CRC table (Ken Raeburn) +- fixed "make uninstall" for shared libraries +- use Tracev instead of Trace in infblock.c +- in example.c use correct compressed length for test_sync +- suppress +vnocompatwarnings in configure for HPUX (not always supported) + +Changes in 1.0.7 (20 Jan 1998) +- fix gzseek which was broken in write mode +- return error for gzseek to negative absolute position +- fix configure for Linux (Chun-Chung Chen) +- increase stack space for MSC (Tim Wegner) +- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant) +- define EXPORTVA for gzprintf (Gilles Vollant) +- added man page zlib.3 (Rick Rodgers) +- for contrib/untgz, fix makedir() and improve Makefile + +- check gzseek in write mode in example.c +- allocate extra buffer for seeks only if gzseek is actually called +- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant) +- add inflateSyncPoint in zconf.h +- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def + +Changes in 1.0.6 (19 Jan 1998) +- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and + gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code) +- Fix a deflate bug occurring only with compression level 0 (thanks to + Andy Buckler for finding this one). +- In minigzip, pass transparently also the first byte for .Z files. +- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress() +- check Z_FINISH in inflate (thanks to Marc Schluper) +- Implement deflateCopy (thanks to Adam Costello) +- make static libraries by default in configure, add --shared option. +- move MSDOS or Windows specific files to directory msdos +- suppress the notion of partial flush to simplify the interface + (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4) +- suppress history buffer provided by application to simplify the interface + (this feature was not implemented anyway in 1.0.4) +- next_in and avail_in must be initialized before calling inflateInit or + inflateInit2 +- add EXPORT in all exported functions (for Windows DLL) +- added Makefile.nt (thanks to Stephen Williams) +- added the unsupported "contrib" directory: + contrib/asm386/ by Gilles Vollant + 386 asm code replacing longest_match(). + contrib/iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + contrib/iostream2/ by Tyge Løvset + Another C++ I/O streams interface + contrib/untgz/ by "Pedro A. Aranda Guti\irrez" + A very simple tar.gz file extractor using zlib + contrib/visual-basic.txt by Carlos Rios + How to use compress(), uncompress() and the gz* functions from VB. +- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression + level) in minigzip (thanks to Tom Lane) + +- use const for rommable constants in deflate +- added test for gzseek and gztell in example.c +- add undocumented function inflateSyncPoint() (hack for Paul Mackerras) +- add undocumented function zError to convert error code to string + (for Tim Smithers) +- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code. +- Use default memcpy for Symantec MSDOS compiler. +- Add EXPORT keyword for check_func (needed for Windows DLL) +- add current directory to LD_LIBRARY_PATH for "make test" +- create also a link for libz.so.1 +- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura) +- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX) +- added -soname for Linux in configure (Chun-Chung Chen, +- assign numbers to the exported functions in zlib.def (for Windows DLL) +- add advice in zlib.h for best usage of deflateSetDictionary +- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn) +- allow compilation with ANSI keywords only enabled for TurboC in large model +- avoid "versionString"[0] (Borland bug) +- add NEED_DUMMY_RETURN for Borland +- use variable z_verbose for tracing in debug mode (L. Peter Deutsch). +- allow compilation with CC +- defined STDC for OS/2 (David Charlap) +- limit external names to 8 chars for MVS (Thomas Lund) +- in minigzip.c, use static buffers only for 16-bit systems +- fix suffix check for "minigzip -d foo.gz" +- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee) +- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau) +- added makelcc.bat for lcc-win32 (Tom St Denis) +- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe) +- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion. +- check for unistd.h in configure (for off_t) +- remove useless check parameter in inflate_blocks_free +- avoid useless assignment of s->check to itself in inflate_blocks_new +- do not flush twice in gzclose (thanks to Ken Raeburn) +- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h +- use NO_ERRNO_H instead of enumeration of operating systems with errno.h +- work around buggy fclose on pipes for HP/UX +- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson) +- fix configure if CC is already equal to gcc + +Changes in 1.0.5 (3 Jan 98) +- Fix inflate to terminate gracefully when fed corrupted or invalid data +- Use const for rommable constants in inflate +- Eliminate memory leaks on error conditions in inflate +- Removed some vestigial code in inflate +- Update web address in README + +Changes in 1.0.4 (24 Jul 96) +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too. +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) +- use z_error only for DEBUG (avoid problem with DLLs) + +Changes in 1.0.3 (2 Jul 96) +- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS + small and medium models; this makes the library incompatible with previous + versions for these models. (No effect in large model or on other systems.) +- return OK instead of BUF_ERROR if previous deflate call returned with + avail_out as zero but there is nothing to do +- added memcmp for non STDC compilers +- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly) +- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO) +- better check for 16-bit mode MSC (avoids problem with Symantec) + +Changes in 1.0.2 (23 May 96) +- added Windows DLL support +- added a function zlibVersion (for the DLL support) +- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model) +- Bytef is define's instead of typedef'd only for Borland C +- avoid reading uninitialized memory in example.c +- mention in README that the zlib format is now RFC1950 +- updated Makefile.dj2 +- added algorithm.doc + +Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion] +- fix array overlay in deflate.c which sometimes caused bad compressed data +- fix inflate bug with empty stored block +- fix MSDOS medium model which was broken in 0.99 +- fix deflateParams() which could generated bad compressed data. +- Bytef is define'd instead of typedef'ed (work around Borland bug) +- added an INDEX file +- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32), + Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas) +- speed up adler32 for modern machines without auto-increment +- added -ansi for IRIX in configure +- static_init_done in trees.c is an int +- define unlink as delete for VMS +- fix configure for QNX +- add configure branch for SCO and HPUX +- avoid many warnings (unused variables, dead assignments, etc...) +- no fdopen for BeOS +- fix the Watcom fix for 32 bit mode (define FAR as empty) +- removed redefinition of Byte for MKWERKS +- work around an MWKERKS bug (incorrect merge of all .h files) + +Changes in 0.99 (27 Jan 96) +- allow preset dictionary shared between compressor and decompressor +- allow compression level 0 (no compression) +- add deflateParams in zlib.h: allow dynamic change of compression level + and compression strategy. +- test large buffers and deflateParams in example.c +- add optional "configure" to build zlib as a shared library +- suppress Makefile.qnx, use configure instead +- fixed deflate for 64-bit systems (detected on Cray) +- fixed inflate_blocks for 64-bit systems (detected on Alpha) +- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2) +- always return Z_BUF_ERROR when deflate() has nothing to do +- deflateInit and inflateInit are now macros to allow version checking +- prefix all global functions and types with z_ with -DZ_PREFIX +- make falloc completely reentrant (inftrees.c) +- fixed very unlikely race condition in ct_static_init +- free in reverse order of allocation to help memory manager +- use zlib-1.0/* instead of zlib/* inside the tar.gz +- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith + -Wconversion -Wstrict-prototypes -Wmissing-prototypes" +- allow gzread on concatenated .gz files +- deflateEnd now returns Z_DATA_ERROR if it was premature +- deflate is finally (?) fully deterministic (no matches beyond end of input) +- Document Z_SYNC_FLUSH +- add uninstall in Makefile +- Check for __cpluplus in zlib.h +- Better test in ct_align for partial flush +- avoid harmless warnings for Borland C++ +- initialize hash_head in deflate.c +- avoid warning on fdopen (gzio.c) for HP cc -Aa +- include stdlib.h for STDC compilers +- include errno.h for Cray +- ignore error if ranlib doesn't exist +- call ranlib twice for NeXTSTEP +- use exec_prefix instead of prefix for libz.a +- renamed ct_* as _tr_* to avoid conflict with applications +- clear z->msg in inflateInit2 before any error return +- initialize opaque in example.c, gzio.c, deflate.c and inflate.c +- fixed typo in zconf.h (_GNUC__ => __GNUC__) +- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode) +- fix typo in Make_vms.com (f$trnlnm -> f$getsyi) +- in fcalloc, normalize pointer if size > 65520 bytes +- don't use special fcalloc for 32 bit Borland C++ +- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc... +- use Z_BINARY instead of BINARY +- document that gzclose after gzdopen will close the file +- allow "a" as mode in gzopen. +- fix error checking in gzread +- allow skipping .gz extra-field on pipes +- added reference to Perl interface in README +- put the crc table in FAR data (I dislike more and more the medium model :) +- added get_crc_table +- added a dimension to all arrays (Borland C can't count). +- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast +- guard against multiple inclusion of *.h (for precompiled header on Mac) +- Watcom C pretends to be Microsoft C small model even in 32 bit mode. +- don't use unsized arrays to avoid silly warnings by Visual C++: + warning C4746: 'inflate_mask' : unsized array treated as '__far' + (what's wrong with far data in far model?). +- define enum out of inflate_blocks_state to allow compilation with C++ + +Changes in 0.95 (16 Aug 95) +- fix MSDOS small and medium model (now easier to adapt to any compiler) +- inlined send_bits +- fix the final (:-) bug for deflate with flush (output was correct but + not completely flushed in rare occasions). +- default window size is same for compression and decompression + (it's now sufficient to set MAX_WBITS in zconf.h). +- voidp -> voidpf and voidnp -> voidp (for consistency with other + typedefs and because voidnp was not near in large model). + +Changes in 0.94 (13 Aug 95) +- support MSDOS medium model +- fix deflate with flush (could sometimes generate bad output) +- fix deflateReset (zlib header was incorrectly suppressed) +- added support for VMS +- allow a compression level in gzopen() +- gzflush now calls fflush +- For deflate with flush, flush even if no more input is provided. +- rename libgz.a as libz.a +- avoid complex expression in infcodes.c triggering Turbo C bug +- work around a problem with gcc on Alpha (in INSERT_STRING) +- don't use inline functions (problem with some gcc versions) +- allow renaming of Byte, uInt, etc... with #define. +- avoid warning about (unused) pointer before start of array in deflate.c +- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c +- avoid reserved word 'new' in trees.c + +Changes in 0.93 (25 June 95) +- temporarily disable inline functions +- make deflate deterministic +- give enough lookahead for PARTIAL_FLUSH +- Set binary mode for stdin/stdout in minigzip.c for OS/2 +- don't even use signed char in inflate (not portable enough) +- fix inflate memory leak for segmented architectures + +Changes in 0.92 (3 May 95) +- don't assume that char is signed (problem on SGI) +- Clear bit buffer when starting a stored block +- no memcpy on Pyramid +- suppressed inftest.c +- optimized fill_window, put longest_match inline for gcc +- optimized inflate on stored blocks. +- untabify all sources to simplify patches + +Changes in 0.91 (2 May 95) +- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h +- Document the memory requirements in zconf.h +- added "make install" +- fix sync search logic in inflateSync +- deflate(Z_FULL_FLUSH) now works even if output buffer too short +- after inflateSync, don't scare people with just "lo world" +- added support for DJGPP + +Changes in 0.9 (1 May 95) +- don't assume that zalloc clears the allocated memory (the TurboC bug + was Mark's bug after all :) +- let again gzread copy uncompressed data unchanged (was working in 0.71) +- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented +- added a test of inflateSync in example.c +- moved MAX_WBITS to zconf.h because users might want to change that. +- document explicitly that zalloc(64K) on MSDOS must return a normalized + pointer (zero offset) +- added Makefiles for Microsoft C, Turbo C, Borland C++ +- faster crc32() + +Changes in 0.8 (29 April 95) +- added fast inflate (inffast.c) +- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this + is incompatible with previous versions of zlib which returned Z_OK. +- work around a TurboC compiler bug (bad code for b << 0, see infutil.h) + (actually that was not a compiler bug, see 0.81 above) +- gzread no longer reads one extra byte in certain cases +- In gzio destroy(), don't reference a freed structure +- avoid many warnings for MSDOS +- avoid the ERROR symbol which is used by MS Windows + +Changes in 0.71 (14 April 95) +- Fixed more MSDOS compilation problems :( There is still a bug with + TurboC large model. + +Changes in 0.7 (14 April 95) +- Added full inflate support. +- Simplified the crc32() interface. The pre- and post-conditioning + (one's complement) is now done inside crc32(). WARNING: this is + incompatible with previous versions; see zlib.h for the new usage. + +Changes in 0.61 (12 April 95) +- workaround for a bug in TurboC. example and minigzip now work on MSDOS. + +Changes in 0.6 (11 April 95) +- added minigzip.c +- added gzdopen to reopen a file descriptor as gzFile +- added transparent reading of non-gziped files in gzread. +- fixed bug in gzread (don't read crc as data) +- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose). +- don't allocate big arrays in the stack (for MSDOS) +- fix some MSDOS compilation problems + +Changes in 0.5: +- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but + not yet Z_FULL_FLUSH. +- support decompression but only in a single step (forced Z_FINISH) +- added opaque object for zalloc and zfree. +- added deflateReset and inflateReset +- added a variable zlib_version for consistency checking. +- renamed the 'filter' parameter of deflateInit2 as 'strategy'. + Added Z_FILTERED and Z_HUFFMAN_ONLY constants. + +Changes in 0.4: +- avoid "zip" everywhere, use zlib instead of ziplib. +- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush + if compression method == 8. +- added adler32 and crc32 +- renamed deflateOptions as deflateInit2, call one or the other but not both +- added the method parameter for deflateInit2. +- added inflateInit2 +- simplied considerably deflateInit and inflateInit by not supporting + user-provided history buffer. This is supported only in deflateInit2 + and inflateInit2. + +Changes in 0.3: +- prefix all macro names with Z_ +- use Z_FINISH instead of deflateEnd to finish compression. +- added Z_HUFFMAN_ONLY +- added gzerror() diff --git a/test/zlib/zlib-1.2.8/FAQ b/test/zlib/zlib-1.2.8/FAQ new file mode 100644 index 000000000..99b7cf92e --- /dev/null +++ b/test/zlib/zlib-1.2.8/FAQ @@ -0,0 +1,368 @@ + + Frequently Asked Questions about zlib + + +If your question is not there, please check the zlib home page +http://zlib.net/ which may have more recent information. +The lastest zlib FAQ is at http://zlib.net/zlib_faq.html + + + 1. Is zlib Y2K-compliant? + + Yes. zlib doesn't handle dates. + + 2. Where can I get a Windows DLL version? + + The zlib sources can be compiled without change to produce a DLL. See the + file win32/DLL_FAQ.txt in the zlib distribution. Pointers to the + precompiled DLL are found in the zlib web site at http://zlib.net/ . + + 3. Where can I get a Visual Basic interface to zlib? + + See + * http://marknelson.us/1997/01/01/zlib-engine/ + * win32/DLL_FAQ.txt in the zlib distribution + + 4. compress() returns Z_BUF_ERROR. + + Make sure that before the call of compress(), the length of the compressed + buffer is equal to the available size of the compressed buffer and not + zero. For Visual Basic, check that this parameter is passed by reference + ("as any"), not by value ("as long"). + + 5. deflate() or inflate() returns Z_BUF_ERROR. + + Before making the call, make sure that avail_in and avail_out are not zero. + When setting the parameter flush equal to Z_FINISH, also make sure that + avail_out is big enough to allow processing all pending input. Note that a + Z_BUF_ERROR is not fatal--another call to deflate() or inflate() can be + made with more input or output space. A Z_BUF_ERROR may in fact be + unavoidable depending on how the functions are used, since it is not + possible to tell whether or not there is more output pending when + strm.avail_out returns with zero. See http://zlib.net/zlib_how.html for a + heavily annotated example. + + 6. Where's the zlib documentation (man pages, etc.)? + + It's in zlib.h . Examples of zlib usage are in the files test/example.c + and test/minigzip.c, with more in examples/ . + + 7. Why don't you use GNU autoconf or libtool or ...? + + Because we would like to keep zlib as a very small and simple package. + zlib is rather portable and doesn't need much configuration. + + 8. I found a bug in zlib. + + Most of the time, such problems are due to an incorrect usage of zlib. + Please try to reproduce the problem with a small program and send the + corresponding source to us at zlib@gzip.org . Do not send multi-megabyte + data files without prior agreement. + + 9. Why do I get "undefined reference to gzputc"? + + If "make test" produces something like + + example.o(.text+0x154): undefined reference to `gzputc' + + check that you don't have old files libz.* in /usr/lib, /usr/local/lib or + /usr/X11R6/lib. Remove any old versions, then do "make install". + +10. I need a Delphi interface to zlib. + + See the contrib/delphi directory in the zlib distribution. + +11. Can zlib handle .zip archives? + + Not by itself, no. See the directory contrib/minizip in the zlib + distribution. + +12. Can zlib handle .Z files? + + No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt + the code of uncompress on your own. + +13. How can I make a Unix shared library? + + By default a shared (and a static) library is built for Unix. So: + + make distclean + ./configure + make + +14. How do I install a shared zlib library on Unix? + + After the above, then: + + make install + + However, many flavors of Unix come with a shared zlib already installed. + Before going to the trouble of compiling a shared version of zlib and + trying to install it, you may want to check if it's already there! If you + can #include , it's there. The -lz option will probably link to + it. You can check the version at the top of zlib.h or with the + ZLIB_VERSION symbol defined in zlib.h . + +15. I have a question about OttoPDF. + + We are not the authors of OttoPDF. The real author is on the OttoPDF web + site: Joel Hainley, jhainley@myndkryme.com. + +16. Can zlib decode Flate data in an Adobe PDF file? + + Yes. See http://www.pdflib.com/ . To modify PDF forms, see + http://sourceforge.net/projects/acroformtool/ . + +17. Why am I getting this "register_frame_info not found" error on Solaris? + + After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib + generates an error such as: + + ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so: + symbol __register_frame_info: referenced symbol not found + + The symbol __register_frame_info is not part of zlib, it is generated by + the C compiler (cc or gcc). You must recompile applications using zlib + which have this problem. This problem is specific to Solaris. See + http://www.sunfreeware.com for Solaris versions of zlib and applications + using zlib. + +18. Why does gzip give an error on a file I make with compress/deflate? + + The compress and deflate functions produce data in the zlib format, which + is different and incompatible with the gzip format. The gz* functions in + zlib on the other hand use the gzip format. Both the zlib and gzip formats + use the same compressed data format internally, but have different headers + and trailers around the compressed data. + +19. Ok, so why are there two different formats? + + The gzip format was designed to retain the directory information about a + single file, such as the name and last modification date. The zlib format + on the other hand was designed for in-memory and communication channel + applications, and has a much more compact header and trailer and uses a + faster integrity check than gzip. + +20. Well that's nice, but how do I make a gzip file in memory? + + You can request that deflate write the gzip format instead of the zlib + format using deflateInit2(). You can also request that inflate decode the + gzip format using inflateInit2(). Read zlib.h for more details. + +21. Is zlib thread-safe? + + Yes. However any library routines that zlib uses and any application- + provided memory allocation routines must also be thread-safe. zlib's gz* + functions use stdio library routines, and most of zlib's functions use the + library memory allocation routines by default. zlib's *Init* functions + allow for the application to provide custom memory allocation routines. + + Of course, you should only operate on any given zlib or gzip stream from a + single thread at a time. + +22. Can I use zlib in my commercial application? + + Yes. Please read the license in zlib.h. + +23. Is zlib under the GNU license? + + No. Please read the license in zlib.h. + +24. The license says that altered source versions must be "plainly marked". So + what exactly do I need to do to meet that requirement? + + You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In + particular, the final version number needs to be changed to "f", and an + identification string should be appended to ZLIB_VERSION. Version numbers + x.x.x.f are reserved for modifications to zlib by others than the zlib + maintainers. For example, if the version of the base zlib you are altering + is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and + ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also + update the version strings in deflate.c and inftrees.c. + + For altered source distributions, you should also note the origin and + nature of the changes in zlib.h, as well as in ChangeLog and README, along + with the dates of the alterations. The origin should include at least your + name (or your company's name), and an email address to contact for help or + issues with the library. + + Note that distributing a compiled zlib library along with zlib.h and + zconf.h is also a source distribution, and so you should change + ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes + in zlib.h as you would for a full source distribution. + +25. Will zlib work on a big-endian or little-endian architecture, and can I + exchange compressed data between them? + + Yes and yes. + +26. Will zlib work on a 64-bit machine? + + Yes. It has been tested on 64-bit machines, and has no dependence on any + data types being limited to 32-bits in length. If you have any + difficulties, please provide a complete problem report to zlib@gzip.org + +27. Will zlib decompress data from the PKWare Data Compression Library? + + No. The PKWare DCL uses a completely different compressed data format than + does PKZIP and zlib. However, you can look in zlib's contrib/blast + directory for a possible solution to your problem. + +28. Can I access data randomly in a compressed stream? + + No, not without some preparation. If when compressing you periodically use + Z_FULL_FLUSH, carefully write all the pending data at those points, and + keep an index of those locations, then you can start decompression at those + points. You have to be careful to not use Z_FULL_FLUSH too often, since it + can significantly degrade compression. Alternatively, you can scan a + deflate stream once to generate an index, and then use that index for + random access. See examples/zran.c . + +29. Does zlib work on MVS, OS/390, CICS, etc.? + + It has in the past, but we have not heard of any recent evidence. There + were working ports of zlib 1.1.4 to MVS, but those links no longer work. + If you know of recent, successful applications of zlib on these operating + systems, please let us know. Thanks. + +30. Is there some simpler, easier to read version of inflate I can look at to + understand the deflate format? + + First off, you should read RFC 1951. Second, yes. Look in zlib's + contrib/puff directory. + +31. Does zlib infringe on any patents? + + As far as we know, no. In fact, that was originally the whole point behind + zlib. Look here for some more information: + + http://www.gzip.org/#faq11 + +32. Can zlib work with greater than 4 GB of data? + + Yes. inflate() and deflate() will process any amount of data correctly. + Each call of inflate() or deflate() is limited to input and output chunks + of the maximum value that can be stored in the compiler's "unsigned int" + type, but there is no limit to the number of chunks. Note however that the + strm.total_in and strm_total_out counters may be limited to 4 GB. These + counters are provided as a convenience and are not used internally by + inflate() or deflate(). The application can easily set up its own counters + updated after each call of inflate() or deflate() to count beyond 4 GB. + compress() and uncompress() may be limited to 4 GB, since they operate in a + single call. gzseek() and gztell() may be limited to 4 GB depending on how + zlib is compiled. See the zlibCompileFlags() function in zlib.h. + + The word "may" appears several times above since there is a 4 GB limit only + if the compiler's "long" type is 32 bits. If the compiler's "long" type is + 64 bits, then the limit is 16 exabytes. + +33. Does zlib have any security vulnerabilities? + + The only one that we are aware of is potentially in gzprintf(). If zlib is + compiled to use sprintf() or vsprintf(), then there is no protection + against a buffer overflow of an 8K string space (or other value as set by + gzbuffer()), other than the caller of gzprintf() assuring that the output + will not exceed 8K. On the other hand, if zlib is compiled to use + snprintf() or vsnprintf(), which should normally be the case, then there is + no vulnerability. The ./configure script will display warnings if an + insecure variation of sprintf() will be used by gzprintf(). Also the + zlibCompileFlags() function will return information on what variant of + sprintf() is used by gzprintf(). + + If you don't have snprintf() or vsnprintf() and would like one, you can + find a portable implementation here: + + http://www.ijs.si/software/snprintf/ + + Note that you should be using the most recent version of zlib. Versions + 1.1.3 and before were subject to a double-free vulnerability, and versions + 1.2.1 and 1.2.2 were subject to an access exception when decompressing + invalid compressed data. + +34. Is there a Java version of zlib? + + Probably what you want is to use zlib in Java. zlib is already included + as part of the Java SDK in the java.util.zip package. If you really want + a version of zlib written in the Java language, look on the zlib home + page for links: http://zlib.net/ . + +35. I get this or that compiler or source-code scanner warning when I crank it + up to maximally-pedantic. Can't you guys write proper code? + + Many years ago, we gave up attempting to avoid warnings on every compiler + in the universe. It just got to be a waste of time, and some compilers + were downright silly as well as contradicted each other. So now, we simply + make sure that the code always works. + +36. Valgrind (or some similar memory access checker) says that deflate is + performing a conditional jump that depends on an uninitialized value. + Isn't that a bug? + + No. That is intentional for performance reasons, and the output of deflate + is not affected. This only started showing up recently since zlib 1.2.x + uses malloc() by default for allocations, whereas earlier versions used + calloc(), which zeros out the allocated memory. Even though the code was + correct, versions 1.2.4 and later was changed to not stimulate these + checkers. + +37. Will zlib read the (insert any ancient or arcane format here) compressed + data format? + + Probably not. Look in the comp.compression FAQ for pointers to various + formats and associated software. + +38. How can I encrypt/decrypt zip files with zlib? + + zlib doesn't support encryption. The original PKZIP encryption is very + weak and can be broken with freely available programs. To get strong + encryption, use GnuPG, http://www.gnupg.org/ , which already includes zlib + compression. For PKZIP compatible "encryption", look at + http://www.info-zip.org/ + +39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings? + + "gzip" is the gzip format, and "deflate" is the zlib format. They should + probably have called the second one "zlib" instead to avoid confusion with + the raw deflate compressed data format. While the HTTP 1.1 RFC 2616 + correctly points to the zlib specification in RFC 1950 for the "deflate" + transfer encoding, there have been reports of servers and browsers that + incorrectly produce or expect raw deflate data per the deflate + specification in RFC 1951, most notably Microsoft. So even though the + "deflate" transfer encoding using the zlib format would be the more + efficient approach (and in fact exactly what the zlib format was designed + for), using the "gzip" transfer encoding is probably more reliable due to + an unfortunate choice of name on the part of the HTTP 1.1 authors. + + Bottom line: use the gzip format for HTTP 1.1 encoding. + +40. Does zlib support the new "Deflate64" format introduced by PKWare? + + No. PKWare has apparently decided to keep that format proprietary, since + they have not documented it as they have previous compression formats. In + any case, the compression improvements are so modest compared to other more + modern approaches, that it's not worth the effort to implement. + +41. I'm having a problem with the zip functions in zlib, can you help? + + There are no zip functions in zlib. You are probably using minizip by + Giles Vollant, which is found in the contrib directory of zlib. It is not + part of zlib. In fact none of the stuff in contrib is part of zlib. The + files in there are not supported by the zlib authors. You need to contact + the authors of the respective contribution for help. + +42. The match.asm code in contrib is under the GNU General Public License. + Since it's part of zlib, doesn't that mean that all of zlib falls under the + GNU GPL? + + No. The files in contrib are not part of zlib. They were contributed by + other authors and are provided as a convenience to the user within the zlib + distribution. Each item in contrib has its own license. + +43. Is zlib subject to export controls? What is its ECCN? + + zlib is not subject to export controls, and so is classified as EAR99. + +44. Can you please sign these lengthy legal documents and fax them back to us + so that we can use your software in our product? + + No. Go away. Shoo. diff --git a/test/zlib/zlib-1.2.8/INDEX b/test/zlib/zlib-1.2.8/INDEX new file mode 100644 index 000000000..2ba064120 --- /dev/null +++ b/test/zlib/zlib-1.2.8/INDEX @@ -0,0 +1,68 @@ +CMakeLists.txt cmake build file +ChangeLog history of changes +FAQ Frequently Asked Questions about zlib +INDEX this file +Makefile dummy Makefile that tells you to ./configure +Makefile.in template for Unix Makefile +README guess what +configure configure script for Unix +make_vms.com makefile for VMS +test/example.c zlib usages examples for build testing +test/minigzip.c minimal gzip-like functionality for build testing +test/infcover.c inf*.c code coverage for build coverage testing +treebuild.xml XML description of source file dependencies +zconf.h.cmakein zconf.h template for cmake +zconf.h.in zconf.h template for configure +zlib.3 Man page for zlib +zlib.3.pdf Man page in PDF format +zlib.map Linux symbol information +zlib.pc.in Template for pkg-config descriptor +zlib.pc.cmakein zlib.pc template for cmake +zlib2ansi perl script to convert source files for C++ compilation + +amiga/ makefiles for Amiga SAS C +as400/ makefiles for AS/400 +doc/ documentation for formats and algorithms +msdos/ makefiles for MSDOS +nintendods/ makefile for Nintendo DS +old/ makefiles for various architectures and zlib documentation + files that have not yet been updated for zlib 1.2.x +qnx/ makefiles for QNX +watcom/ makefiles for OpenWatcom +win32/ makefiles for Windows + + zlib public header files (required for library use): +zconf.h +zlib.h + + private source files used to build the zlib library: +adler32.c +compress.c +crc32.c +crc32.h +deflate.c +deflate.h +gzclose.c +gzguts.h +gzlib.c +gzread.c +gzwrite.c +infback.c +inffast.c +inffast.h +inffixed.h +inflate.c +inflate.h +inftrees.c +inftrees.h +trees.c +trees.h +uncompr.c +zutil.c +zutil.h + + source files for sample programs +See examples/README.examples + + unsupported contributions by third parties +See contrib/README.contrib diff --git a/test/zlib/zlib-1.2.8/Makefile b/test/zlib/zlib-1.2.8/Makefile new file mode 100644 index 000000000..6bba86c73 --- /dev/null +++ b/test/zlib/zlib-1.2.8/Makefile @@ -0,0 +1,5 @@ +all: + -@echo "Please use ./configure first. Thank you." + +distclean: + make -f Makefile.in distclean diff --git a/test/zlib/zlib-1.2.8/Makefile.in b/test/zlib/zlib-1.2.8/Makefile.in new file mode 100644 index 000000000..c61aa3008 --- /dev/null +++ b/test/zlib/zlib-1.2.8/Makefile.in @@ -0,0 +1,288 @@ +# Makefile for zlib +# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# ./configure; make test +# Normally configure builds both a static and a shared library. +# If you want to build just a static library, use: ./configure --static + +# To use the asm code, type: +# cp contrib/asm?86/match.S ./match.S +# make LOC=-DASMV OBJA=match.o + +# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: +# make install +# To install in $HOME instead of /usr/local, use: +# make install prefix=$HOME + +CC=cc + +CFLAGS=-O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DDEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +SFLAGS=-O +LDFLAGS= +TEST_LDFLAGS=-L. libz.a +LDSHARED=$(CC) +CPP=$(CC) -E + +STATICLIB=libz.a +SHAREDLIB=libz.so +SHAREDLIBV=libz.so.1.2.8 +SHAREDLIBM=libz.so.1 +LIBS=$(STATICLIB) $(SHAREDLIBV) + +AR=ar +ARFLAGS=rc +RANLIB=ranlib +LDCONFIG=ldconfig +LDSHAREDLIBC=-lc +TAR=tar +SHELL=/bin/sh +EXE= + +prefix = /usr/local +exec_prefix = ${prefix} +libdir = ${exec_prefix}/lib +sharedlibdir = ${libdir} +includedir = ${prefix}/include +mandir = ${prefix}/share/man +man3dir = ${mandir}/man3 +pkgconfigdir = ${libdir}/pkgconfig + +OBJZ = adler32.o crc32.o deflate.o infback.o inffast.o inflate.o inftrees.o trees.o zutil.o +OBJG = compress.o uncompr.o gzclose.o gzlib.o gzread.o gzwrite.o +OBJC = $(OBJZ) $(OBJG) + +PIC_OBJZ = adler32.lo crc32.lo deflate.lo infback.lo inffast.lo inflate.lo inftrees.lo trees.lo zutil.lo +PIC_OBJG = compress.lo uncompr.lo gzclose.lo gzlib.lo gzread.lo gzwrite.lo +PIC_OBJC = $(PIC_OBJZ) $(PIC_OBJG) + +# to use the asm code: make OBJA=match.o, PIC_OBJA=match.lo +OBJA = +PIC_OBJA = + +OBJS = $(OBJC) $(OBJA) + +PIC_OBJS = $(PIC_OBJC) $(PIC_OBJA) + +all: static shared + +static: example$(EXE) minigzip$(EXE) + +shared: examplesh$(EXE) minigzipsh$(EXE) + +all64: example64$(EXE) minigzip64$(EXE) + +check: test + +test: all teststatic testshared + +teststatic: static + @TMPST=tmpst_$$; \ + if echo hello world | ./minigzip | ./minigzip -d && ./example $$TMPST ; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; false; \ + fi; \ + rm -f $$TMPST + +testshared: shared + @LD_LIBRARY_PATH=`pwd`:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + LD_LIBRARYN32_PATH=`pwd`:$(LD_LIBRARYN32_PATH) ; export LD_LIBRARYN32_PATH; \ + DYLD_LIBRARY_PATH=`pwd`:$(DYLD_LIBRARY_PATH) ; export DYLD_LIBRARY_PATH; \ + SHLIB_PATH=`pwd`:$(SHLIB_PATH) ; export SHLIB_PATH; \ + TMPSH=tmpsh_$$; \ + if echo hello world | ./minigzipsh | ./minigzipsh -d && ./examplesh $$TMPSH; then \ + echo ' *** zlib shared test OK ***'; \ + else \ + echo ' *** zlib shared test FAILED ***'; false; \ + fi; \ + rm -f $$TMPSH + +test64: all64 + @TMP64=tmp64_$$; \ + if echo hello world | ./minigzip64 | ./minigzip64 -d && ./example64 $$TMP64; then \ + echo ' *** zlib 64-bit test OK ***'; \ + else \ + echo ' *** zlib 64-bit test FAILED ***'; false; \ + fi; \ + rm -f $$TMP64 + +infcover.o: test/infcover.c zlib.h zconf.h + $(CC) $(CFLAGS) -I. -c -o $@ test/infcover.c + +infcover: infcover.o libz.a + $(CC) $(CFLAGS) -o $@ infcover.o libz.a + +cover: infcover + rm -f *.gcda + ./infcover + gcov inf*.c + +libz.a: $(OBJS) + $(AR) $(ARFLAGS) $@ $(OBJS) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +match.o: match.S + $(CPP) match.S > _match.s + $(CC) -c _match.s + mv _match.o match.o + rm -f _match.s + +match.lo: match.S + $(CPP) match.S > _match.s + $(CC) -c -fPIC _match.s + mv _match.o match.lo + rm -f _match.s + +example.o: test/example.c zlib.h zconf.h + $(CC) $(CFLAGS) -I. -c -o $@ test/example.c + +minigzip.o: test/minigzip.c zlib.h zconf.h + $(CC) $(CFLAGS) -I. -c -o $@ test/minigzip.c + +example64.o: test/example.c zlib.h zconf.h + $(CC) $(CFLAGS) -I. -D_FILE_OFFSET_BITS=64 -c -o $@ test/example.c + +minigzip64.o: test/minigzip.c zlib.h zconf.h + $(CC) $(CFLAGS) -I. -D_FILE_OFFSET_BITS=64 -c -o $@ test/minigzip.c + +.SUFFIXES: .lo + +.c.lo: + -@mkdir objs 2>/dev/null || test -d objs + $(CC) $(SFLAGS) -DPIC -c -o objs/$*.o $< + -@mv objs/$*.o $@ + +placebo $(SHAREDLIBV): $(PIC_OBJS) libz.a + $(LDSHARED) $(SFLAGS) -o $@ $(PIC_OBJS) $(LDSHAREDLIBC) $(LDFLAGS) + rm -f $(SHAREDLIB) $(SHAREDLIBM) + ln -s $@ $(SHAREDLIB) + ln -s $@ $(SHAREDLIBM) + -@rmdir objs + +example$(EXE): example.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ example.o $(TEST_LDFLAGS) + +minigzip$(EXE): minigzip.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ minigzip.o $(TEST_LDFLAGS) + +examplesh$(EXE): example.o $(SHAREDLIBV) + $(CC) $(CFLAGS) -o $@ example.o -L. $(SHAREDLIBV) + +minigzipsh$(EXE): minigzip.o $(SHAREDLIBV) + $(CC) $(CFLAGS) -o $@ minigzip.o -L. $(SHAREDLIBV) + +example64$(EXE): example64.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ example64.o $(TEST_LDFLAGS) + +minigzip64$(EXE): minigzip64.o $(STATICLIB) + $(CC) $(CFLAGS) -o $@ minigzip64.o $(TEST_LDFLAGS) + +install-libs: $(LIBS) + -@if [ ! -d $(DESTDIR)$(exec_prefix) ]; then mkdir -p $(DESTDIR)$(exec_prefix); fi + -@if [ ! -d $(DESTDIR)$(libdir) ]; then mkdir -p $(DESTDIR)$(libdir); fi + -@if [ ! -d $(DESTDIR)$(sharedlibdir) ]; then mkdir -p $(DESTDIR)$(sharedlibdir); fi + -@if [ ! -d $(DESTDIR)$(man3dir) ]; then mkdir -p $(DESTDIR)$(man3dir); fi + -@if [ ! -d $(DESTDIR)$(pkgconfigdir) ]; then mkdir -p $(DESTDIR)$(pkgconfigdir); fi + cp $(STATICLIB) $(DESTDIR)$(libdir) + chmod 644 $(DESTDIR)$(libdir)/$(STATICLIB) + -@($(RANLIB) $(DESTDIR)$(libdir)/libz.a || true) >/dev/null 2>&1 + -@if test -n "$(SHAREDLIBV)"; then \ + cp $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir); \ + echo "cp $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)"; \ + chmod 755 $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBV); \ + echo "chmod 755 $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBV)"; \ + rm -f $(DESTDIR)$(sharedlibdir)/$(SHAREDLIB) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBM); \ + ln -s $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIB); \ + ln -s $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBM); \ + ($(LDCONFIG) || true) >/dev/null 2>&1; \ + fi + cp zlib.3 $(DESTDIR)$(man3dir) + chmod 644 $(DESTDIR)$(man3dir)/zlib.3 + cp zlib.pc $(DESTDIR)$(pkgconfigdir) + chmod 644 $(DESTDIR)$(pkgconfigdir)/zlib.pc +# The ranlib in install is needed on NeXTSTEP which checks file times +# ldconfig is for Linux + +install: install-libs + -@if [ ! -d $(DESTDIR)$(includedir) ]; then mkdir -p $(DESTDIR)$(includedir); fi + cp zlib.h zconf.h $(DESTDIR)$(includedir) + chmod 644 $(DESTDIR)$(includedir)/zlib.h $(DESTDIR)$(includedir)/zconf.h + +uninstall: + cd $(DESTDIR)$(includedir) && rm -f zlib.h zconf.h + cd $(DESTDIR)$(libdir) && rm -f libz.a; \ + if test -n "$(SHAREDLIBV)" -a -f $(SHAREDLIBV); then \ + rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \ + fi + cd $(DESTDIR)$(man3dir) && rm -f zlib.3 + cd $(DESTDIR)$(pkgconfigdir) && rm -f zlib.pc + +docs: zlib.3.pdf + +zlib.3.pdf: zlib.3 + groff -mandoc -f H -T ps zlib.3 | ps2pdf - zlib.3.pdf + +zconf.h.cmakein: zconf.h.in + -@ TEMPFILE=zconfh_$$; \ + echo "/#define ZCONF_H/ a\\\\\n#cmakedefine Z_PREFIX\\\\\n#cmakedefine Z_HAVE_UNISTD_H\n" >> $$TEMPFILE &&\ + sed -f $$TEMPFILE zconf.h.in > zconf.h.cmakein &&\ + touch -r zconf.h.in zconf.h.cmakein &&\ + rm $$TEMPFILE + +zconf: zconf.h.in + cp -p zconf.h.in zconf.h + +mostlyclean: clean +clean: + rm -f *.o *.lo *~ \ + example$(EXE) minigzip$(EXE) examplesh$(EXE) minigzipsh$(EXE) \ + example64$(EXE) minigzip64$(EXE) \ + infcover \ + libz.* foo.gz so_locations \ + _match.s maketree contrib/infback9/*.o + rm -rf objs + rm -f *.gcda *.gcno *.gcov + rm -f contrib/infback9/*.gcda contrib/infback9/*.gcno contrib/infback9/*.gcov + +maintainer-clean: distclean +distclean: clean zconf zconf.h.cmakein docs + rm -f Makefile zlib.pc configure.log + -@rm -f .DS_Store + -@printf 'all:\n\t-@echo "Please use ./configure first. Thank you."\n' > Makefile + -@printf '\ndistclean:\n\tmake -f Makefile.in distclean\n' >> Makefile + -@touch -r Makefile.in Makefile + +tags: + etags *.[ch] + +depend: + makedepend -- $(CFLAGS) -- *.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o zutil.o: zutil.h zlib.h zconf.h +gzclose.o gzlib.o gzread.o gzwrite.o: zlib.h zconf.h gzguts.h +compress.o example.o minigzip.o uncompr.o: zlib.h zconf.h +crc32.o: zutil.h zlib.h zconf.h crc32.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +infback.o inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h + +adler32.lo zutil.lo: zutil.h zlib.h zconf.h +gzclose.lo gzlib.lo gzread.lo gzwrite.lo: zlib.h zconf.h gzguts.h +compress.lo example.lo minigzip.lo uncompr.lo: zlib.h zconf.h +crc32.lo: zutil.h zlib.h zconf.h crc32.h +deflate.lo: deflate.h zutil.h zlib.h zconf.h +infback.lo inflate.lo: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h +inffast.lo: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.lo: zutil.h zlib.h zconf.h inftrees.h +trees.lo: deflate.h zutil.h zlib.h zconf.h trees.h diff --git a/test/zlib/zlib-1.2.8/README b/test/zlib/zlib-1.2.8/README new file mode 100644 index 000000000..5ca9d127e --- /dev/null +++ b/test/zlib/zlib-1.2.8/README @@ -0,0 +1,115 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.8 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and +rfc1952 (gzip format). + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example +of the library is given in the file test/example.c which also tests that +the library is working correctly. Another example is given in the file +test/minigzip.c. The compression library itself is composed of all source +files in the root directory. + +To compile all files and run the test program, follow the instructions given at +the top of Makefile.in. In short "./configure; make test", and if that goes +well, "make install" should work for most flavors of Unix. For Windows, use +one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use +make_vms.com. + +Questions about zlib should be sent to , or to Gilles Vollant + for the Windows DLL version. The zlib home page is +http://zlib.net/ . Before reporting a problem, please check this site to +verify that you have the latest version of zlib; otherwise get the latest +version and check whether the problem still exists or not. + +PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. + +Mark Nelson wrote an article about zlib for the Jan. 1997 +issue of Dr. Dobb's Journal; a copy of the article is available at +http://marknelson.us/1997/01/01/zlib-engine/ . + +The changes made in version 1.2.8 are documented in the file ChangeLog. + +Unsupported third party contributions are provided in directory contrib/ . + +zlib is available in Java using the java.util.zip package, documented at +http://java.sun.com/developer/technicalArticles/Programming/compression/ . + +A Perl interface to zlib written by Paul Marquess is available +at CPAN (Comprehensive Perl Archive Network) sites, including +http://search.cpan.org/~pmqs/IO-Compress-Zlib/ . + +A Python interface to zlib written by A.M. Kuchling is +available in Python 1.5 and later versions, see +http://docs.python.org/library/zlib.html . + +zlib is built into tcl: http://wiki.tcl.tk/4610 . + +An experimental package to read and write files in .zip format, written on top +of zlib by Gilles Vollant , is available in the +contrib/minizip directory of zlib. + + +Notes for some targets: + +- For Windows DLL versions, please see win32/DLL_FAQ.txt + +- For 64-bit Irix, deflate.c must be compiled without any optimization. With + -O, one libpng test fails. The test works in 32 bit mode (with the -n32 + compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works + when compiled with cc. + +- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is + necessary to get gzprintf working correctly. This is done by configure. + +- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with + other compilers. Use "make test" to check your compiler. + +- gzdopen is not supported on RISCOS or BEOS. + +- For PalmOs, see http://palmzlib.sourceforge.net/ + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate and + zlib specifications were written by L. Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; they + are too numerous to cite here. + +Copyright notice: + + (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. diff --git a/test/zlib/zlib-1.2.8/adler32.c b/test/zlib/zlib-1.2.8/adler32.c new file mode 100644 index 000000000..a868f073d --- /dev/null +++ b/test/zlib/zlib-1.2.8/adler32.c @@ -0,0 +1,179 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-2011 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" + +#define local static + +local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); + +#define BASE 65521 /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* use NO_DIVIDE if your processor does not do division in hardware -- + try it both ways to see which is faster */ +#ifdef NO_DIVIDE +/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 + (thank you to John Reiser for pointing this out) */ +# define CHOP(a) \ + do { \ + unsigned long tmp = a >> 16; \ + a &= 0xffffUL; \ + a += (tmp << 4) - tmp; \ + } while (0) +# define MOD28(a) \ + do { \ + CHOP(a); \ + if (a >= BASE) a -= BASE; \ + } while (0) +# define MOD(a) \ + do { \ + CHOP(a); \ + MOD28(a); \ + } while (0) +# define MOD63(a) \ + do { /* this assumes a is not negative */ \ + z_off64_t tmp = a >> 32; \ + a &= 0xffffffffL; \ + a += (tmp << 8) - (tmp << 5) + tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + tmp = a >> 16; \ + a &= 0xffffL; \ + a += (tmp << 4) - tmp; \ + if (a >= BASE) a -= BASE; \ + } while (0) +#else +# define MOD(a) a %= BASE +# define MOD28(a) a %= BASE +# define MOD63(a) a %= BASE +#endif + +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long sum2; + unsigned n; + + /* split Adler-32 into component sums */ + sum2 = (adler >> 16) & 0xffff; + adler &= 0xffff; + + /* in case user likes doing a byte at a time, keep it fast */ + if (len == 1) { + adler += buf[0]; + if (adler >= BASE) + adler -= BASE; + sum2 += adler; + if (sum2 >= BASE) + sum2 -= BASE; + return adler | (sum2 << 16); + } + + /* initial Adler-32 value (deferred check for len == 1 speed) */ + if (buf == Z_NULL) + return 1L; + + /* in case short lengths are provided, keep it somewhat fast */ + if (len < 16) { + while (len--) { + adler += *buf++; + sum2 += adler; + } + if (adler >= BASE) + adler -= BASE; + MOD28(sum2); /* only added so many BASE's */ + return adler | (sum2 << 16); + } + + /* do length NMAX blocks -- requires just one modulo operation */ + while (len >= NMAX) { + len -= NMAX; + n = NMAX / 16; /* NMAX is divisible by 16 */ + do { + DO16(buf); /* 16 sums unrolled */ + buf += 16; + } while (--n); + MOD(adler); + MOD(sum2); + } + + /* do remaining bytes (less than NMAX, still just one modulo) */ + if (len) { /* avoid modulos if none remaining */ + while (len >= 16) { + len -= 16; + DO16(buf); + buf += 16; + } + while (len--) { + adler += *buf++; + sum2 += adler; + } + MOD(adler); + MOD(sum2); + } + + /* return recombined sums */ + return adler | (sum2 << 16); +} + +/* ========================================================================= */ +local uLong adler32_combine_(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + unsigned long sum1; + unsigned long sum2; + unsigned rem; + + /* for negative len, return invalid adler32 as a clue for debugging */ + if (len2 < 0) + return 0xffffffffUL; + + /* the derivation of this formula is left as an exercise for the reader */ + MOD63(len2); /* assumes len2 >= 0 */ + rem = (unsigned)len2; + sum1 = adler1 & 0xffff; + sum2 = rem * sum1; + MOD(sum2); + sum1 += (adler2 & 0xffff) + BASE - 1; + sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; + if (sum1 >= BASE) sum1 -= BASE; + if (sum1 >= BASE) sum1 -= BASE; + if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 >= BASE) sum2 -= BASE; + return sum1 | (sum2 << 16); +} + +/* ========================================================================= */ +uLong ZEXPORT adler32_combine(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} + +uLong ZEXPORT adler32_combine64(adler1, adler2, len2) + uLong adler1; + uLong adler2; + z_off64_t len2; +{ + return adler32_combine_(adler1, adler2, len2); +} diff --git a/test/zlib/zlib-1.2.8/amiga/Makefile.pup b/test/zlib/zlib-1.2.8/amiga/Makefile.pup new file mode 100644 index 000000000..8940c120f --- /dev/null +++ b/test/zlib/zlib-1.2.8/amiga/Makefile.pup @@ -0,0 +1,69 @@ +# Amiga powerUP (TM) Makefile +# makefile for libpng and SAS C V6.58/7.00 PPC compiler +# Copyright (C) 1998 by Andreas R. Kleinert + +LIBNAME = libzip.a + +CC = scppc +CFLAGS = NOSTKCHK NOSINT OPTIMIZE OPTGO OPTPEEP OPTINLOCAL OPTINL \ + OPTLOOP OPTRDEP=8 OPTDEP=8 OPTCOMP=8 NOVER +AR = ppc-amigaos-ar cr +RANLIB = ppc-amigaos-ranlib +LD = ppc-amigaos-ld -r +LDFLAGS = -o +LDLIBS = LIB:scppc.a LIB:end.o +RM = delete quiet + +OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \ + uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o + +TEST_OBJS = example.o minigzip.o + +all: example minigzip + +check: test +test: all + example + echo hello world | minigzip | minigzip -d + +$(LIBNAME): $(OBJS) + $(AR) $@ $(OBJS) + -$(RANLIB) $@ + +example: example.o $(LIBNAME) + $(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS) + +minigzip: minigzip.o $(LIBNAME) + $(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS) + +mostlyclean: clean +clean: + $(RM) *.o example minigzip $(LIBNAME) foo.gz + +zip: + zip -ul9 zlib README ChangeLog Makefile Make????.??? Makefile.?? \ + descrip.mms *.[ch] + +tgz: + cd ..; tar cfz zlib/zlib.tgz zlib/README zlib/ChangeLog zlib/Makefile \ + zlib/Make????.??? zlib/Makefile.?? zlib/descrip.mms zlib/*.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: crc32.h zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzclose.o: zlib.h zconf.h gzguts.h +gzlib.o: zlib.h zconf.h gzguts.h +gzread.o: zlib.h zconf.h gzguts.h +gzwrite.o: zlib.h zconf.h gzguts.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/test/zlib/zlib-1.2.8/amiga/Makefile.sas b/test/zlib/zlib-1.2.8/amiga/Makefile.sas new file mode 100644 index 000000000..749e29152 --- /dev/null +++ b/test/zlib/zlib-1.2.8/amiga/Makefile.sas @@ -0,0 +1,68 @@ +# SMakefile for zlib +# Modified from the standard UNIX Makefile Copyright Jean-loup Gailly +# Osma Ahvenlampi +# Amiga, SAS/C 6.56 & Smake + +CC=sc +CFLAGS=OPT +#CFLAGS=OPT CPU=68030 +#CFLAGS=DEBUG=LINE +LDFLAGS=LIB z.lib + +SCOPTIONS=OPTSCHED OPTINLINE OPTALIAS OPTTIME OPTINLOCAL STRMERGE \ + NOICONS PARMS=BOTH NOSTACKCHECK UTILLIB NOVERSION ERRORREXX \ + DEF=POSTINC + +OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \ + uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o + +TEST_OBJS = example.o minigzip.o + +all: SCOPTIONS example minigzip + +check: test +test: all + example + echo hello world | minigzip | minigzip -d + +install: z.lib + copy clone zlib.h zconf.h INCLUDE: + copy clone z.lib LIB: + +z.lib: $(OBJS) + oml z.lib r $(OBJS) + +example: example.o z.lib + $(CC) $(CFLAGS) LINK TO $@ example.o $(LDFLAGS) + +minigzip: minigzip.o z.lib + $(CC) $(CFLAGS) LINK TO $@ minigzip.o $(LDFLAGS) + +mostlyclean: clean +clean: + -delete force quiet example minigzip *.o z.lib foo.gz *.lnk SCOPTIONS + +SCOPTIONS: Makefile.sas + copy to $@ 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, level); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} + +/* =========================================================================== + */ +int ZEXPORT compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); +} + +/* =========================================================================== + If the default memLevel or windowBits for deflateInit() is changed, then + this function needs to be updated. + */ +uLong ZEXPORT compressBound (sourceLen) + uLong sourceLen; +{ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13; +} diff --git a/test/zlib/zlib-1.2.8/configure b/test/zlib/zlib-1.2.8/configure new file mode 100644 index 000000000..b77a8a8cf --- /dev/null +++ b/test/zlib/zlib-1.2.8/configure @@ -0,0 +1,831 @@ +#!/bin/sh +# configure script for zlib. +# +# Normally configure builds both a static and a shared library. +# If you want to build just a static library, use: ./configure --static +# +# To impose specific compiler or flags or install directory, use for example: +# prefix=$HOME CC=cc CFLAGS="-O4" ./configure +# or for csh/tcsh users: +# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure) + +# Incorrect settings of CC or CFLAGS may prevent creating a shared library. +# If you have problems, try without defining CC and CFLAGS before reporting +# an error. + +# start off configure.log +echo -------------------- >> configure.log +echo $0 $* >> configure.log +date >> configure.log + +# set command prefix for cross-compilation +if [ -n "${CHOST}" ]; then + uname="`echo "${CHOST}" | sed -e 's/^[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)-.*$/\1/'`" + CROSS_PREFIX="${CHOST}-" +fi + +# destination name for static library +STATICLIB=libz.a + +# extract zlib version numbers from zlib.h +VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h` +VER3=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\\.[0-9]*\).*/\1/p' < zlib.h` +VER2=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\)\\..*/\1/p' < zlib.h` +VER1=`sed -n -e '/VERSION "/s/.*"\([0-9]*\)\\..*/\1/p' < zlib.h` + +# establish commands for library building +if "${CROSS_PREFIX}ar" --version >/dev/null 2>/dev/null || test $? -lt 126; then + AR=${AR-"${CROSS_PREFIX}ar"} + test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log +else + AR=${AR-"ar"} + test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log +fi +ARFLAGS=${ARFLAGS-"rc"} +if "${CROSS_PREFIX}ranlib" --version >/dev/null 2>/dev/null || test $? -lt 126; then + RANLIB=${RANLIB-"${CROSS_PREFIX}ranlib"} + test -n "${CROSS_PREFIX}" && echo Using ${RANLIB} | tee -a configure.log +else + RANLIB=${RANLIB-"ranlib"} +fi +if "${CROSS_PREFIX}nm" --version >/dev/null 2>/dev/null || test $? -lt 126; then + NM=${NM-"${CROSS_PREFIX}nm"} + test -n "${CROSS_PREFIX}" && echo Using ${NM} | tee -a configure.log +else + NM=${NM-"nm"} +fi + +# set defaults before processing command line options +LDCONFIG=${LDCONFIG-"ldconfig"} +LDSHAREDLIBC="${LDSHAREDLIBC--lc}" +ARCHS= +prefix=${prefix-/usr/local} +exec_prefix=${exec_prefix-'${prefix}'} +libdir=${libdir-'${exec_prefix}/lib'} +sharedlibdir=${sharedlibdir-'${libdir}'} +includedir=${includedir-'${prefix}/include'} +mandir=${mandir-'${prefix}/share/man'} +shared_ext='.so' +shared=1 +solo=0 +cover=0 +zprefix=0 +zconst=0 +build64=0 +gcc=0 +old_cc="$CC" +old_cflags="$CFLAGS" +OBJC='$(OBJZ) $(OBJG)' +PIC_OBJC='$(PIC_OBJZ) $(PIC_OBJG)' + +# leave this script, optionally in a bad way +leave() +{ + if test "$*" != "0"; then + echo "** $0 aborting." | tee -a configure.log + fi + rm -f $test.[co] $test $test$shared_ext $test.gcno ./--version + echo -------------------- >> configure.log + echo >> configure.log + echo >> configure.log + exit $1 +} + +# process command line options +while test $# -ge 1 +do +case "$1" in + -h* | --help) + echo 'usage:' | tee -a configure.log + echo ' configure [--const] [--zprefix] [--prefix=PREFIX] [--eprefix=EXPREFIX]' | tee -a configure.log + echo ' [--static] [--64] [--libdir=LIBDIR] [--sharedlibdir=LIBDIR]' | tee -a configure.log + echo ' [--includedir=INCLUDEDIR] [--archs="-arch i386 -arch x86_64"]' | tee -a configure.log + exit 0 ;; + -p*=* | --prefix=*) prefix=`echo $1 | sed 's/.*=//'`; shift ;; + -e*=* | --eprefix=*) exec_prefix=`echo $1 | sed 's/.*=//'`; shift ;; + -l*=* | --libdir=*) libdir=`echo $1 | sed 's/.*=//'`; shift ;; + --sharedlibdir=*) sharedlibdir=`echo $1 | sed 's/.*=//'`; shift ;; + -i*=* | --includedir=*) includedir=`echo $1 | sed 's/.*=//'`;shift ;; + -u*=* | --uname=*) uname=`echo $1 | sed 's/.*=//'`;shift ;; + -p* | --prefix) prefix="$2"; shift; shift ;; + -e* | --eprefix) exec_prefix="$2"; shift; shift ;; + -l* | --libdir) libdir="$2"; shift; shift ;; + -i* | --includedir) includedir="$2"; shift; shift ;; + -s* | --shared | --enable-shared) shared=1; shift ;; + -t | --static) shared=0; shift ;; + --solo) solo=1; shift ;; + --cover) cover=1; shift ;; + -z* | --zprefix) zprefix=1; shift ;; + -6* | --64) build64=1; shift ;; + -a*=* | --archs=*) ARCHS=`echo $1 | sed 's/.*=//'`; shift ;; + --sysconfdir=*) echo "ignored option: --sysconfdir" | tee -a configure.log; shift ;; + --localstatedir=*) echo "ignored option: --localstatedir" | tee -a configure.log; shift ;; + -c* | --const) zconst=1; shift ;; + *) + echo "unknown option: $1" | tee -a configure.log + echo "$0 --help for help" | tee -a configure.log + leave 1;; + esac +done + +# temporary file name +test=ztest$$ + +# put arguments in log, also put test file in log if used in arguments +show() +{ + case "$*" in + *$test.c*) + echo === $test.c === >> configure.log + cat $test.c >> configure.log + echo === >> configure.log;; + esac + echo $* >> configure.log +} + +# check for gcc vs. cc and set compile and link flags based on the system identified by uname +cat > $test.c <&1` in + *gcc*) gcc=1 ;; +esac + +show $cc -c $test.c +if test "$gcc" -eq 1 && ($cc -c $test.c) >> configure.log 2>&1; then + echo ... using gcc >> configure.log + CC="$cc" + CFLAGS="${CFLAGS--O3} ${ARCHS}" + SFLAGS="${CFLAGS--O3} -fPIC" + LDFLAGS="${LDFLAGS} ${ARCHS}" + if test $build64 -eq 1; then + CFLAGS="${CFLAGS} -m64" + SFLAGS="${SFLAGS} -m64" + fi + if test "${ZLIBGCCWARN}" = "YES"; then + if test "$zconst" -eq 1; then + CFLAGS="${CFLAGS} -Wall -Wextra -Wcast-qual -pedantic -DZLIB_CONST" + else + CFLAGS="${CFLAGS} -Wall -Wextra -pedantic" + fi + fi + if test -z "$uname"; then + uname=`(uname -s || echo unknown) 2>/dev/null` + fi + case "$uname" in + Linux* | linux* | GNU | GNU/* | solaris*) + LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map"} ;; + *BSD | *bsd* | DragonFly) + LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map"} + LDCONFIG="ldconfig -m" ;; + CYGWIN* | Cygwin* | cygwin* | OS/2*) + EXE='.exe' ;; + MINGW* | mingw*) +# temporary bypass + rm -f $test.[co] $test $test$shared_ext + echo "Please use win32/Makefile.gcc instead." | tee -a configure.log + leave 1 + LDSHARED=${LDSHARED-"$cc -shared"} + LDSHAREDLIBC="" + EXE='.exe' ;; + QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4 + # (alain.bonnefoy@icbt.com) + LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"} ;; + HP-UX*) + LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"} + case `(uname -m || echo unknown) 2>/dev/null` in + ia64) + shared_ext='.so' + SHAREDLIB='libz.so' ;; + *) + shared_ext='.sl' + SHAREDLIB='libz.sl' ;; + esac ;; + Darwin* | darwin*) + shared_ext='.dylib' + SHAREDLIB=libz$shared_ext + SHAREDLIBV=libz.$VER$shared_ext + SHAREDLIBM=libz.$VER1$shared_ext + LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name $libdir/$SHAREDLIBM -compatibility_version $VER1 -current_version $VER3"} + if libtool -V 2>&1 | grep Apple > /dev/null; then + AR="libtool" + else + AR="/usr/bin/libtool" + fi + ARFLAGS="-o" ;; + *) LDSHARED=${LDSHARED-"$cc -shared"} ;; + esac +else + # find system name and corresponding cc options + CC=${CC-cc} + gcc=0 + echo ... using $CC >> configure.log + if test -z "$uname"; then + uname=`(uname -sr || echo unknown) 2>/dev/null` + fi + case "$uname" in + HP-UX*) SFLAGS=${CFLAGS-"-O +z"} + CFLAGS=${CFLAGS-"-O"} +# LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"} + LDSHARED=${LDSHARED-"ld -b"} + case `(uname -m || echo unknown) 2>/dev/null` in + ia64) + shared_ext='.so' + SHAREDLIB='libz.so' ;; + *) + shared_ext='.sl' + SHAREDLIB='libz.sl' ;; + esac ;; + IRIX*) SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."} + CFLAGS=${CFLAGS-"-ansi -O2"} + LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so.1"} ;; + OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"} + CFLAGS=${CFLAGS-"-O -std1"} + LDFLAGS="${LDFLAGS} -Wl,-rpath,." + LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"} ;; + OSF1*) SFLAGS=${CFLAGS-"-O -std1"} + CFLAGS=${CFLAGS-"-O -std1"} + LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so.1"} ;; + QNX*) SFLAGS=${CFLAGS-"-4 -O"} + CFLAGS=${CFLAGS-"-4 -O"} + LDSHARED=${LDSHARED-"cc"} + RANLIB=${RANLIB-"true"} + AR="cc" + ARFLAGS="-A" ;; + SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "} + CFLAGS=${CFLAGS-"-O3"} + LDSHARED=${LDSHARED-"cc -dy -KPIC -G"} ;; + SunOS\ 5* | solaris*) + LDSHARED=${LDSHARED-"cc -G -h libz$shared_ext.$VER1"} + SFLAGS=${CFLAGS-"-fast -KPIC"} + CFLAGS=${CFLAGS-"-fast"} + if test $build64 -eq 1; then + # old versions of SunPRO/Workshop/Studio don't support -m64, + # but newer ones do. Check for it. + flag64=`$CC -flags | egrep -- '^-m64'` + if test x"$flag64" != x"" ; then + CFLAGS="${CFLAGS} -m64" + SFLAGS="${SFLAGS} -m64" + else + case `(uname -m || echo unknown) 2>/dev/null` in + i86*) + SFLAGS="$SFLAGS -xarch=amd64" + CFLAGS="$CFLAGS -xarch=amd64" ;; + *) + SFLAGS="$SFLAGS -xarch=v9" + CFLAGS="$CFLAGS -xarch=v9" ;; + esac + fi + fi + ;; + SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"} + CFLAGS=${CFLAGS-"-O2"} + LDSHARED=${LDSHARED-"ld"} ;; + SunStudio\ 9*) SFLAGS=${CFLAGS-"-fast -xcode=pic32 -xtarget=ultra3 -xarch=v9b"} + CFLAGS=${CFLAGS-"-fast -xtarget=ultra3 -xarch=v9b"} + LDSHARED=${LDSHARED-"cc -xarch=v9b"} ;; + UNIX_System_V\ 4.2.0) + SFLAGS=${CFLAGS-"-KPIC -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"} ;; + UNIX_SV\ 4.2MP) + SFLAGS=${CFLAGS-"-Kconform_pic -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"} ;; + OpenUNIX\ 5) + SFLAGS=${CFLAGS-"-KPIC -O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -G"} ;; + AIX*) # Courtesy of dbakker@arrayasolutions.com + SFLAGS=${CFLAGS-"-O -qmaxmem=8192"} + CFLAGS=${CFLAGS-"-O -qmaxmem=8192"} + LDSHARED=${LDSHARED-"xlc -G"} ;; + # send working options for other systems to zlib@gzip.org + *) SFLAGS=${CFLAGS-"-O"} + CFLAGS=${CFLAGS-"-O"} + LDSHARED=${LDSHARED-"cc -shared"} ;; + esac +fi + +# destination names for shared library if not defined above +SHAREDLIB=${SHAREDLIB-"libz$shared_ext"} +SHAREDLIBV=${SHAREDLIBV-"libz$shared_ext.$VER"} +SHAREDLIBM=${SHAREDLIBM-"libz$shared_ext.$VER1"} + +echo >> configure.log + +# define functions for testing compiler and library characteristics and logging the results + +cat > $test.c </dev/null; then + try() + { + show $* + test "`( $* ) 2>&1 | tee -a configure.log`" = "" + } + echo - using any output from compiler to indicate an error >> configure.log +else +try() +{ + show $* + ( $* ) >> configure.log 2>&1 + ret=$? + if test $ret -ne 0; then + echo "(exit code "$ret")" >> configure.log + fi + return $ret +} +fi + +tryboth() +{ + show $* + got=`( $* ) 2>&1` + ret=$? + printf %s "$got" >> configure.log + if test $ret -ne 0; then + return $ret + fi + test "$got" = "" +} + +cat > $test.c << EOF +int foo() { return 0; } +EOF +echo "Checking for obsessive-compulsive compiler options..." >> configure.log +if try $CC -c $CFLAGS $test.c; then + : +else + echo "Compiler error reporting is too harsh for $0 (perhaps remove -Werror)." | tee -a configure.log + leave 1 +fi + +echo >> configure.log + +# see if shared library build supported +cat > $test.c <> configure.log + show "$NM $test.o | grep _hello" + if test "`$NM $test.o | grep _hello | tee -a configure.log`" = ""; then + CPP="$CPP -DNO_UNDERLINE" + echo Checking for underline in external names... No. | tee -a configure.log + else + echo Checking for underline in external names... Yes. | tee -a configure.log + fi ;; +esac + +echo >> configure.log + +# check for large file support, and if none, check for fseeko() +cat > $test.c < +off64_t dummy = 0; +EOF +if try $CC -c $CFLAGS -D_LARGEFILE64_SOURCE=1 $test.c; then + CFLAGS="${CFLAGS} -D_LARGEFILE64_SOURCE=1" + SFLAGS="${SFLAGS} -D_LARGEFILE64_SOURCE=1" + ALL="${ALL} all64" + TEST="${TEST} test64" + echo "Checking for off64_t... Yes." | tee -a configure.log + echo "Checking for fseeko... Yes." | tee -a configure.log +else + echo "Checking for off64_t... No." | tee -a configure.log + echo >> configure.log + cat > $test.c < +int main(void) { + fseeko(NULL, 0, 0); + return 0; +} +EOF + if try $CC $CFLAGS -o $test $test.c; then + echo "Checking for fseeko... Yes." | tee -a configure.log + else + CFLAGS="${CFLAGS} -DNO_FSEEKO" + SFLAGS="${SFLAGS} -DNO_FSEEKO" + echo "Checking for fseeko... No." | tee -a configure.log + fi +fi + +echo >> configure.log + +# check for strerror() for use by gz* functions +cat > $test.c < +#include +int main() { return strlen(strerror(errno)); } +EOF +if try $CC $CFLAGS -o $test $test.c; then + echo "Checking for strerror... Yes." | tee -a configure.log +else + CFLAGS="${CFLAGS} -DNO_STRERROR" + SFLAGS="${SFLAGS} -DNO_STRERROR" + echo "Checking for strerror... No." | tee -a configure.log +fi + +# copy clean zconf.h for subsequent edits +cp -p zconf.h.in zconf.h + +echo >> configure.log + +# check for unistd.h and save result in zconf.h +cat > $test.c < +int main() { return 0; } +EOF +if try $CC -c $CFLAGS $test.c; then + sed < zconf.h "/^#ifdef HAVE_UNISTD_H.* may be/s/def HAVE_UNISTD_H\(.*\) may be/ 1\1 was/" > zconf.temp.h + mv zconf.temp.h zconf.h + echo "Checking for unistd.h... Yes." | tee -a configure.log +else + echo "Checking for unistd.h... No." | tee -a configure.log +fi + +echo >> configure.log + +# check for stdarg.h and save result in zconf.h +cat > $test.c < +int main() { return 0; } +EOF +if try $CC -c $CFLAGS $test.c; then + sed < zconf.h "/^#ifdef HAVE_STDARG_H.* may be/s/def HAVE_STDARG_H\(.*\) may be/ 1\1 was/" > zconf.temp.h + mv zconf.temp.h zconf.h + echo "Checking for stdarg.h... Yes." | tee -a configure.log +else + echo "Checking for stdarg.h... No." | tee -a configure.log +fi + +# if the z_ prefix was requested, save that in zconf.h +if test $zprefix -eq 1; then + sed < zconf.h "/#ifdef Z_PREFIX.* may be/s/def Z_PREFIX\(.*\) may be/ 1\1 was/" > zconf.temp.h + mv zconf.temp.h zconf.h + echo >> configure.log + echo "Using z_ prefix on all symbols." | tee -a configure.log +fi + +# if --solo compilation was requested, save that in zconf.h and remove gz stuff from object lists +if test $solo -eq 1; then + sed '/#define ZCONF_H/a\ +#define Z_SOLO + +' < zconf.h > zconf.temp.h + mv zconf.temp.h zconf.h +OBJC='$(OBJZ)' +PIC_OBJC='$(PIC_OBJZ)' +fi + +# if code coverage testing was requested, use older gcc if defined, e.g. "gcc-4.2" on Mac OS X +if test $cover -eq 1; then + CFLAGS="${CFLAGS} -fprofile-arcs -ftest-coverage" + if test -n "$GCC_CLASSIC"; then + CC=$GCC_CLASSIC + fi +fi + +echo >> configure.log + +# conduct a series of tests to resolve eight possible cases of using "vs" or "s" printf functions +# (using stdarg or not), with or without "n" (proving size of buffer), and with or without a +# return value. The most secure result is vsnprintf() with a return value. snprintf() with a +# return value is secure as well, but then gzprintf() will be limited to 20 arguments. +cat > $test.c < +#include +#include "zconf.h" +int main() +{ +#ifndef STDC + choke me +#endif + return 0; +} +EOF +if try $CC -c $CFLAGS $test.c; then + echo "Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf()." | tee -a configure.log + + echo >> configure.log + cat > $test.c < +#include +int mytest(const char *fmt, ...) +{ + char buf[20]; + va_list ap; + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return 0; +} +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + if try $CC $CFLAGS -o $test $test.c; then + echo "Checking for vsnprintf() in stdio.h... Yes." | tee -a configure.log + + echo >> configure.log + cat >$test.c < +#include +int mytest(const char *fmt, ...) +{ + int n; + char buf[20]; + va_list ap; + va_start(ap, fmt); + n = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + return n; +} +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if try $CC -c $CFLAGS $test.c; then + echo "Checking for return value of vsnprintf()... Yes." | tee -a configure.log + else + CFLAGS="$CFLAGS -DHAS_vsnprintf_void" + SFLAGS="$SFLAGS -DHAS_vsnprintf_void" + echo "Checking for return value of vsnprintf()... No." | tee -a configure.log + echo " WARNING: apparently vsnprintf() does not return a value. zlib" | tee -a configure.log + echo " can build but will be open to possible string-format security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + fi + else + CFLAGS="$CFLAGS -DNO_vsnprintf" + SFLAGS="$SFLAGS -DNO_vsnprintf" + echo "Checking for vsnprintf() in stdio.h... No." | tee -a configure.log + echo " WARNING: vsnprintf() not found, falling back to vsprintf(). zlib" | tee -a configure.log + echo " can build but will be open to possible buffer-overflow security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + + echo >> configure.log + cat >$test.c < +#include +int mytest(const char *fmt, ...) +{ + int n; + char buf[20]; + va_list ap; + va_start(ap, fmt); + n = vsprintf(buf, fmt, ap); + va_end(ap); + return n; +} +int main() +{ + return (mytest("Hello%d\n", 1)); +} +EOF + + if try $CC -c $CFLAGS $test.c; then + echo "Checking for return value of vsprintf()... Yes." | tee -a configure.log + else + CFLAGS="$CFLAGS -DHAS_vsprintf_void" + SFLAGS="$SFLAGS -DHAS_vsprintf_void" + echo "Checking for return value of vsprintf()... No." | tee -a configure.log + echo " WARNING: apparently vsprintf() does not return a value. zlib" | tee -a configure.log + echo " can build but will be open to possible string-format security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + fi + fi +else + echo "Checking whether to use vs[n]printf() or s[n]printf()... using s[n]printf()." | tee -a configure.log + + echo >> configure.log + cat >$test.c < +int mytest() +{ + char buf[20]; + snprintf(buf, sizeof(buf), "%s", "foo"); + return 0; +} +int main() +{ + return (mytest()); +} +EOF + + if try $CC $CFLAGS -o $test $test.c; then + echo "Checking for snprintf() in stdio.h... Yes." | tee -a configure.log + + echo >> configure.log + cat >$test.c < +int mytest() +{ + char buf[20]; + return snprintf(buf, sizeof(buf), "%s", "foo"); +} +int main() +{ + return (mytest()); +} +EOF + + if try $CC -c $CFLAGS $test.c; then + echo "Checking for return value of snprintf()... Yes." | tee -a configure.log + else + CFLAGS="$CFLAGS -DHAS_snprintf_void" + SFLAGS="$SFLAGS -DHAS_snprintf_void" + echo "Checking for return value of snprintf()... No." | tee -a configure.log + echo " WARNING: apparently snprintf() does not return a value. zlib" | tee -a configure.log + echo " can build but will be open to possible string-format security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + fi + else + CFLAGS="$CFLAGS -DNO_snprintf" + SFLAGS="$SFLAGS -DNO_snprintf" + echo "Checking for snprintf() in stdio.h... No." | tee -a configure.log + echo " WARNING: snprintf() not found, falling back to sprintf(). zlib" | tee -a configure.log + echo " can build but will be open to possible buffer-overflow security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + + echo >> configure.log + cat >$test.c < +int mytest() +{ + char buf[20]; + return sprintf(buf, "%s", "foo"); +} +int main() +{ + return (mytest()); +} +EOF + + if try $CC -c $CFLAGS $test.c; then + echo "Checking for return value of sprintf()... Yes." | tee -a configure.log + else + CFLAGS="$CFLAGS -DHAS_sprintf_void" + SFLAGS="$SFLAGS -DHAS_sprintf_void" + echo "Checking for return value of sprintf()... No." | tee -a configure.log + echo " WARNING: apparently sprintf() does not return a value. zlib" | tee -a configure.log + echo " can build but will be open to possible string-format security" | tee -a configure.log + echo " vulnerabilities." | tee -a configure.log + fi + fi +fi + +# see if we can hide zlib internal symbols that are linked between separate source files +if test "$gcc" -eq 1; then + echo >> configure.log + cat > $test.c <> configure.log +echo ALL = $ALL >> configure.log +echo AR = $AR >> configure.log +echo ARFLAGS = $ARFLAGS >> configure.log +echo CC = $CC >> configure.log +echo CFLAGS = $CFLAGS >> configure.log +echo CPP = $CPP >> configure.log +echo EXE = $EXE >> configure.log +echo LDCONFIG = $LDCONFIG >> configure.log +echo LDFLAGS = $LDFLAGS >> configure.log +echo LDSHARED = $LDSHARED >> configure.log +echo LDSHAREDLIBC = $LDSHAREDLIBC >> configure.log +echo OBJC = $OBJC >> configure.log +echo PIC_OBJC = $PIC_OBJC >> configure.log +echo RANLIB = $RANLIB >> configure.log +echo SFLAGS = $SFLAGS >> configure.log +echo SHAREDLIB = $SHAREDLIB >> configure.log +echo SHAREDLIBM = $SHAREDLIBM >> configure.log +echo SHAREDLIBV = $SHAREDLIBV >> configure.log +echo STATICLIB = $STATICLIB >> configure.log +echo TEST = $TEST >> configure.log +echo VER = $VER >> configure.log +echo Z_U4 = $Z_U4 >> configure.log +echo exec_prefix = $exec_prefix >> configure.log +echo includedir = $includedir >> configure.log +echo libdir = $libdir >> configure.log +echo mandir = $mandir >> configure.log +echo prefix = $prefix >> configure.log +echo sharedlibdir = $sharedlibdir >> configure.log +echo uname = $uname >> configure.log + +# udpate Makefile with the configure results +sed < Makefile.in " +/^CC *=/s#=.*#=$CC# +/^CFLAGS *=/s#=.*#=$CFLAGS# +/^SFLAGS *=/s#=.*#=$SFLAGS# +/^LDFLAGS *=/s#=.*#=$LDFLAGS# +/^LDSHARED *=/s#=.*#=$LDSHARED# +/^CPP *=/s#=.*#=$CPP# +/^STATICLIB *=/s#=.*#=$STATICLIB# +/^SHAREDLIB *=/s#=.*#=$SHAREDLIB# +/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV# +/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM# +/^AR *=/s#=.*#=$AR# +/^ARFLAGS *=/s#=.*#=$ARFLAGS# +/^RANLIB *=/s#=.*#=$RANLIB# +/^LDCONFIG *=/s#=.*#=$LDCONFIG# +/^LDSHAREDLIBC *=/s#=.*#=$LDSHAREDLIBC# +/^EXE *=/s#=.*#=$EXE# +/^prefix *=/s#=.*#=$prefix# +/^exec_prefix *=/s#=.*#=$exec_prefix# +/^libdir *=/s#=.*#=$libdir# +/^sharedlibdir *=/s#=.*#=$sharedlibdir# +/^includedir *=/s#=.*#=$includedir# +/^mandir *=/s#=.*#=$mandir# +/^OBJC *=/s#=.*#= $OBJC# +/^PIC_OBJC *=/s#=.*#= $PIC_OBJC# +/^all: */s#:.*#: $ALL# +/^test: */s#:.*#: $TEST# +" > Makefile + +# create zlib.pc with the configure results +sed < zlib.pc.in " +/^CC *=/s#=.*#=$CC# +/^CFLAGS *=/s#=.*#=$CFLAGS# +/^CPP *=/s#=.*#=$CPP# +/^LDSHARED *=/s#=.*#=$LDSHARED# +/^STATICLIB *=/s#=.*#=$STATICLIB# +/^SHAREDLIB *=/s#=.*#=$SHAREDLIB# +/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV# +/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM# +/^AR *=/s#=.*#=$AR# +/^ARFLAGS *=/s#=.*#=$ARFLAGS# +/^RANLIB *=/s#=.*#=$RANLIB# +/^EXE *=/s#=.*#=$EXE# +/^prefix *=/s#=.*#=$prefix# +/^exec_prefix *=/s#=.*#=$exec_prefix# +/^libdir *=/s#=.*#=$libdir# +/^sharedlibdir *=/s#=.*#=$sharedlibdir# +/^includedir *=/s#=.*#=$includedir# +/^mandir *=/s#=.*#=$mandir# +/^LDFLAGS *=/s#=.*#=$LDFLAGS# +" | sed -e " +s/\@VERSION\@/$VER/g; +" > zlib.pc + +# done +leave 0 diff --git a/test/zlib/zlib-1.2.8/contrib/README.contrib b/test/zlib/zlib-1.2.8/contrib/README.contrib new file mode 100644 index 000000000..c66349b7c --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/README.contrib @@ -0,0 +1,78 @@ +All files under this contrib directory are UNSUPPORTED. There were +provided by users of zlib and were not tested by the authors of zlib. +Use at your own risk. Please contact the authors of the contributions +for help about these, not the zlib authors. Thanks. + + +ada/ by Dmitriy Anisimkov + Support for Ada + See http://zlib-ada.sourceforge.net/ + +amd64/ by Mikhail Teterin + asm code for AMD64 + See patch at http://www.freebsd.org/cgi/query-pr.cgi?pr=bin/96393 + +asm686/ by Brian Raiter + asm code for Pentium and PPro/PII, using the AT&T (GNU as) syntax + See http://www.muppetlabs.com/~breadbox/software/assembly.html + +blast/ by Mark Adler + Decompressor for output of PKWare Data Compression Library (DCL) + +delphi/ by Cosmin Truta + Support for Delphi and C++ Builder + +dotzlib/ by Henrik Ravn + Support for Microsoft .Net and Visual C++ .Net + +gcc_gvmat64/by Gilles Vollant + GCC Version of x86 64-bit (AMD64 and Intel EM64t) code for x64 + assembler to replace longest_match() and inflate_fast() + +infback9/ by Mark Adler + Unsupported diffs to infback to decode the deflate64 format + +inflate86/ by Chris Anderson + Tuned x86 gcc asm code to replace inflate_fast() + +iostream/ by Kevin Ruland + A C++ I/O streams interface to the zlib gz* functions + +iostream2/ by Tyge Løvset + Another C++ I/O streams interface + +iostream3/ by Ludwig Schwardt + and Kevin Ruland + Yet another C++ I/O streams interface + +masmx64/ by Gilles Vollant + x86 64-bit (AMD64 and Intel EM64t) code for x64 assembler to + replace longest_match() and inflate_fast(), also masm x86 + 64-bits translation of Chris Anderson inflate_fast() + +masmx86/ by Gilles Vollant + x86 asm code to replace longest_match() and inflate_fast(), + for Visual C++ and MASM (32 bits). + Based on Brian Raiter (asm686) and Chris Anderson (inflate86) + +minizip/ by Gilles Vollant + Mini zip and unzip based on zlib + Includes Zip64 support by Mathias Svensson + See http://www.winimage.com/zLibDll/unzip.html + +pascal/ by Bob Dellaca et al. + Support for Pascal + +puff/ by Mark Adler + Small, low memory usage inflate. Also serves to provide an + unambiguous description of the deflate format. + +testzlib/ by Gilles Vollant + Example of the use of zlib + +untgz/ by Pedro A. Aranda Gutierrez + A very simple tar.gz file extractor using zlib + +vstudio/ by Gilles Vollant + Building a minizip-enhanced zlib with Microsoft Visual Studio + Includes vc11 from kreuzerkrieg and vc12 from davispuh diff --git a/test/zlib/zlib-1.2.8/contrib/ada/buffer_demo.adb b/test/zlib/zlib-1.2.8/contrib/ada/buffer_demo.adb new file mode 100644 index 000000000..46b863810 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/ada/buffer_demo.adb @@ -0,0 +1,106 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2004 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- +-- +-- $Id: buffer_demo.adb,v 1.3 2004/09/06 06:55:35 vagul Exp $ + +-- This demo program provided by Dr Steve Sangwine +-- +-- Demonstration of a problem with Zlib-Ada (already fixed) when a buffer +-- of exactly the correct size is used for decompressed data, and the last +-- few bytes passed in to Zlib are checksum bytes. + +-- This program compresses a string of text, and then decompresses the +-- compressed text into a buffer of the same size as the original text. + +with Ada.Streams; use Ada.Streams; +with Ada.Text_IO; + +with ZLib; use ZLib; + +procedure Buffer_Demo is + EOL : Character renames ASCII.LF; + Text : constant String + := "Four score and seven years ago our fathers brought forth," & EOL & + "upon this continent, a new nation, conceived in liberty," & EOL & + "and dedicated to the proposition that `all men are created equal'."; + + Source : Stream_Element_Array (1 .. Text'Length); + for Source'Address use Text'Address; + +begin + Ada.Text_IO.Put (Text); + Ada.Text_IO.New_Line; + Ada.Text_IO.Put_Line + ("Uncompressed size : " & Positive'Image (Text'Length) & " bytes"); + + declare + Compressed_Data : Stream_Element_Array (1 .. Text'Length); + L : Stream_Element_Offset; + begin + Compress : declare + Compressor : Filter_Type; + I : Stream_Element_Offset; + begin + Deflate_Init (Compressor); + + -- Compress the whole of T at once. + + Translate (Compressor, Source, I, Compressed_Data, L, Finish); + pragma Assert (I = Source'Last); + + Close (Compressor); + + Ada.Text_IO.Put_Line + ("Compressed size : " + & Stream_Element_Offset'Image (L) & " bytes"); + end Compress; + + -- Now we decompress the data, passing short blocks of data to Zlib + -- (because this demonstrates the problem - the last block passed will + -- contain checksum information and there will be no output, only a + -- check inside Zlib that the checksum is correct). + + Decompress : declare + Decompressor : Filter_Type; + + Uncompressed_Data : Stream_Element_Array (1 .. Text'Length); + + Block_Size : constant := 4; + -- This makes sure that the last block contains + -- only Adler checksum data. + + P : Stream_Element_Offset := Compressed_Data'First - 1; + O : Stream_Element_Offset; + begin + Inflate_Init (Decompressor); + + loop + Translate + (Decompressor, + Compressed_Data + (P + 1 .. Stream_Element_Offset'Min (P + Block_Size, L)), + P, + Uncompressed_Data + (Total_Out (Decompressor) + 1 .. Uncompressed_Data'Last), + O, + No_Flush); + + Ada.Text_IO.Put_Line + ("Total in : " & Count'Image (Total_In (Decompressor)) & + ", out : " & Count'Image (Total_Out (Decompressor))); + + exit when P = L; + end loop; + + Ada.Text_IO.New_Line; + Ada.Text_IO.Put_Line + ("Decompressed text matches original text : " + & Boolean'Image (Uncompressed_Data = Source)); + end Decompress; + end; +end Buffer_Demo; diff --git a/test/zlib/zlib-1.2.8/contrib/ada/mtest.adb b/test/zlib/zlib-1.2.8/contrib/ada/mtest.adb new file mode 100644 index 000000000..c4dfd080f --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/ada/mtest.adb @@ -0,0 +1,156 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- +-- Continuous test for ZLib multithreading. If the test would fail +-- we should provide thread safe allocation routines for the Z_Stream. +-- +-- $Id: mtest.adb,v 1.4 2004/07/23 07:49:54 vagul Exp $ + +with ZLib; +with Ada.Streams; +with Ada.Numerics.Discrete_Random; +with Ada.Text_IO; +with Ada.Exceptions; +with Ada.Task_Identification; + +procedure MTest is + use Ada.Streams; + use ZLib; + + Stop : Boolean := False; + + pragma Atomic (Stop); + + subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#; + + package Random_Elements is + new Ada.Numerics.Discrete_Random (Visible_Symbols); + + task type Test_Task; + + task body Test_Task is + Buffer : Stream_Element_Array (1 .. 100_000); + Gen : Random_Elements.Generator; + + Buffer_First : Stream_Element_Offset; + Compare_First : Stream_Element_Offset; + + Deflate : Filter_Type; + Inflate : Filter_Type; + + procedure Further (Item : in Stream_Element_Array); + + procedure Read_Buffer + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + + ------------- + -- Further -- + ------------- + + procedure Further (Item : in Stream_Element_Array) is + + procedure Compare (Item : in Stream_Element_Array); + + ------------- + -- Compare -- + ------------- + + procedure Compare (Item : in Stream_Element_Array) is + Next_First : Stream_Element_Offset := Compare_First + Item'Length; + begin + if Buffer (Compare_First .. Next_First - 1) /= Item then + raise Program_Error; + end if; + + Compare_First := Next_First; + end Compare; + + procedure Compare_Write is new ZLib.Write (Write => Compare); + begin + Compare_Write (Inflate, Item, No_Flush); + end Further; + + ----------------- + -- Read_Buffer -- + ----------------- + + procedure Read_Buffer + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset) + is + Buff_Diff : Stream_Element_Offset := Buffer'Last - Buffer_First; + Next_First : Stream_Element_Offset; + begin + if Item'Length <= Buff_Diff then + Last := Item'Last; + + Next_First := Buffer_First + Item'Length; + + Item := Buffer (Buffer_First .. Next_First - 1); + + Buffer_First := Next_First; + else + Last := Item'First + Buff_Diff; + Item (Item'First .. Last) := Buffer (Buffer_First .. Buffer'Last); + Buffer_First := Buffer'Last + 1; + end if; + end Read_Buffer; + + procedure Translate is new Generic_Translate + (Data_In => Read_Buffer, + Data_Out => Further); + + begin + Random_Elements.Reset (Gen); + + Buffer := (others => 20); + + Main : loop + for J in Buffer'Range loop + Buffer (J) := Random_Elements.Random (Gen); + + Deflate_Init (Deflate); + Inflate_Init (Inflate); + + Buffer_First := Buffer'First; + Compare_First := Buffer'First; + + Translate (Deflate); + + if Compare_First /= Buffer'Last + 1 then + raise Program_Error; + end if; + + Ada.Text_IO.Put_Line + (Ada.Task_Identification.Image + (Ada.Task_Identification.Current_Task) + & Stream_Element_Offset'Image (J) + & ZLib.Count'Image (Total_Out (Deflate))); + + Close (Deflate); + Close (Inflate); + + exit Main when Stop; + end loop; + end loop Main; + exception + when E : others => + Ada.Text_IO.Put_Line (Ada.Exceptions.Exception_Information (E)); + Stop := True; + end Test_Task; + + Test : array (1 .. 4) of Test_Task; + + pragma Unreferenced (Test); + + Dummy : Character; + +begin + Ada.Text_IO.Get_Immediate (Dummy); + Stop := True; +end MTest; diff --git a/test/zlib/zlib-1.2.8/contrib/ada/read.adb b/test/zlib/zlib-1.2.8/contrib/ada/read.adb new file mode 100644 index 000000000..1f2efbfeb --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/ada/read.adb @@ -0,0 +1,156 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: read.adb,v 1.8 2004/05/31 10:53:40 vagul Exp $ + +-- Test/demo program for the generic read interface. + +with Ada.Numerics.Discrete_Random; +with Ada.Streams; +with Ada.Text_IO; + +with ZLib; + +procedure Read is + + use Ada.Streams; + + ------------------------------------ + -- Test configuration parameters -- + ------------------------------------ + + File_Size : Stream_Element_Offset := 100_000; + + Continuous : constant Boolean := False; + -- If this constant is True, the test would be repeated again and again, + -- with increment File_Size for every iteration. + + Header : constant ZLib.Header_Type := ZLib.Default; + -- Do not use Header other than Default in ZLib versions 1.1.4 and older. + + Init_Random : constant := 8; + -- We are using the same random sequence, in case of we catch bug, + -- so we would be able to reproduce it. + + -- End -- + + Pack_Size : Stream_Element_Offset; + Offset : Stream_Element_Offset; + + Filter : ZLib.Filter_Type; + + subtype Visible_Symbols + is Stream_Element range 16#20# .. 16#7E#; + + package Random_Elements is new + Ada.Numerics.Discrete_Random (Visible_Symbols); + + Gen : Random_Elements.Generator; + Period : constant Stream_Element_Offset := 200; + -- Period constant variable for random generator not to be very random. + -- Bigger period, harder random. + + Read_Buffer : Stream_Element_Array (1 .. 2048); + Read_First : Stream_Element_Offset; + Read_Last : Stream_Element_Offset; + + procedure Reset; + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset); + -- this procedure is for generic instantiation of + -- ZLib.Read + -- reading data from the File_In. + + procedure Read is new ZLib.Read + (Read, + Read_Buffer, + Rest_First => Read_First, + Rest_Last => Read_Last); + + ---------- + -- Read -- + ---------- + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) is + begin + Last := Stream_Element_Offset'Min + (Item'Last, + Item'First + File_Size - Offset); + + for J in Item'First .. Last loop + if J < Item'First + Period then + Item (J) := Random_Elements.Random (Gen); + else + Item (J) := Item (J - Period); + end if; + + Offset := Offset + 1; + end loop; + end Read; + + ----------- + -- Reset -- + ----------- + + procedure Reset is + begin + Random_Elements.Reset (Gen, Init_Random); + Pack_Size := 0; + Offset := 1; + Read_First := Read_Buffer'Last + 1; + Read_Last := Read_Buffer'Last; + end Reset; + +begin + Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version); + + loop + for Level in ZLib.Compression_Level'Range loop + + Ada.Text_IO.Put ("Level =" + & ZLib.Compression_Level'Image (Level)); + + -- Deflate using generic instantiation. + + ZLib.Deflate_Init + (Filter, + Level, + Header => Header); + + Reset; + + Ada.Text_IO.Put + (Stream_Element_Offset'Image (File_Size) & " ->"); + + loop + declare + Buffer : Stream_Element_Array (1 .. 1024); + Last : Stream_Element_Offset; + begin + Read (Filter, Buffer, Last); + + Pack_Size := Pack_Size + Last - Buffer'First + 1; + + exit when Last < Buffer'Last; + end; + end loop; + + Ada.Text_IO.Put_Line (Stream_Element_Offset'Image (Pack_Size)); + + ZLib.Close (Filter); + end loop; + + exit when not Continuous; + + File_Size := File_Size + 1; + end loop; +end Read; diff --git a/test/zlib/zlib-1.2.8/contrib/ada/readme.txt b/test/zlib/zlib-1.2.8/contrib/ada/readme.txt new file mode 100644 index 000000000..ce4d2cadf --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/ada/readme.txt @@ -0,0 +1,65 @@ + ZLib for Ada thick binding (ZLib.Ada) + Release 1.3 + +ZLib.Ada is a thick binding interface to the popular ZLib data +compression library, available at http://www.gzip.org/zlib/. +It provides Ada-style access to the ZLib C library. + + + Here are the main changes since ZLib.Ada 1.2: + +- Attension: ZLib.Read generic routine have a initialization requirement + for Read_Last parameter now. It is a bit incompartible with previous version, + but extends functionality, we could use new parameters Allow_Read_Some and + Flush now. + +- Added Is_Open routines to ZLib and ZLib.Streams packages. + +- Add pragma Assert to check Stream_Element is 8 bit. + +- Fix extraction to buffer with exact known decompressed size. Error reported by + Steve Sangwine. + +- Fix definition of ULong (changed to unsigned_long), fix regression on 64 bits + computers. Patch provided by Pascal Obry. + +- Add Status_Error exception definition. + +- Add pragma Assertion that Ada.Streams.Stream_Element size is 8 bit. + + + How to build ZLib.Ada under GNAT + +You should have the ZLib library already build on your computer, before +building ZLib.Ada. Make the directory of ZLib.Ada sources current and +issue the command: + + gnatmake test -largs -L -lz + +Or use the GNAT project file build for GNAT 3.15 or later: + + gnatmake -Pzlib.gpr -L + + + How to build ZLib.Ada under Aonix ObjectAda for Win32 7.2.2 + +1. Make a project with all *.ads and *.adb files from the distribution. +2. Build the libz.a library from the ZLib C sources. +3. Rename libz.a to z.lib. +4. Add the library z.lib to the project. +5. Add the libc.lib library from the ObjectAda distribution to the project. +6. Build the executable using test.adb as a main procedure. + + + How to use ZLib.Ada + +The source files test.adb and read.adb are small demo programs that show +the main functionality of ZLib.Ada. + +The routines from the package specifications are commented. + + +Homepage: http://zlib-ada.sourceforge.net/ +Author: Dmitriy Anisimkov + +Contributors: Pascal Obry , Steve Sangwine diff --git a/test/zlib/zlib-1.2.8/contrib/ada/test.adb b/test/zlib/zlib-1.2.8/contrib/ada/test.adb new file mode 100644 index 000000000..90773acfa --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/ada/test.adb @@ -0,0 +1,463 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: test.adb,v 1.17 2003/08/12 12:13:30 vagul Exp $ + +-- The program has a few aims. +-- 1. Test ZLib.Ada95 thick binding functionality. +-- 2. Show the example of use main functionality of the ZLib.Ada95 binding. +-- 3. Build this program automatically compile all ZLib.Ada95 packages under +-- GNAT Ada95 compiler. + +with ZLib.Streams; +with Ada.Streams.Stream_IO; +with Ada.Numerics.Discrete_Random; + +with Ada.Text_IO; + +with Ada.Calendar; + +procedure Test is + + use Ada.Streams; + use Stream_IO; + + ------------------------------------ + -- Test configuration parameters -- + ------------------------------------ + + File_Size : Count := 100_000; + Continuous : constant Boolean := False; + + Header : constant ZLib.Header_Type := ZLib.Default; + -- ZLib.None; + -- ZLib.Auto; + -- ZLib.GZip; + -- Do not use Header other then Default in ZLib versions 1.1.4 + -- and older. + + Strategy : constant ZLib.Strategy_Type := ZLib.Default_Strategy; + Init_Random : constant := 10; + + -- End -- + + In_File_Name : constant String := "testzlib.in"; + -- Name of the input file + + Z_File_Name : constant String := "testzlib.zlb"; + -- Name of the compressed file. + + Out_File_Name : constant String := "testzlib.out"; + -- Name of the decompressed file. + + File_In : File_Type; + File_Out : File_Type; + File_Back : File_Type; + File_Z : ZLib.Streams.Stream_Type; + + Filter : ZLib.Filter_Type; + + Time_Stamp : Ada.Calendar.Time; + + procedure Generate_File; + -- Generate file of spetsified size with some random data. + -- The random data is repeatable, for the good compression. + + procedure Compare_Streams + (Left, Right : in out Root_Stream_Type'Class); + -- The procedure compearing data in 2 streams. + -- It is for compare data before and after compression/decompression. + + procedure Compare_Files (Left, Right : String); + -- Compare files. Based on the Compare_Streams. + + procedure Copy_Streams + (Source, Target : in out Root_Stream_Type'Class; + Buffer_Size : in Stream_Element_Offset := 1024); + -- Copying data from one stream to another. It is for test stream + -- interface of the library. + + procedure Data_In + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset); + -- this procedure is for generic instantiation of + -- ZLib.Generic_Translate. + -- reading data from the File_In. + + procedure Data_Out (Item : in Stream_Element_Array); + -- this procedure is for generic instantiation of + -- ZLib.Generic_Translate. + -- writing data to the File_Out. + + procedure Stamp; + -- Store the timestamp to the local variable. + + procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count); + -- Print the time statistic with the message. + + procedure Translate is new ZLib.Generic_Translate + (Data_In => Data_In, + Data_Out => Data_Out); + -- This procedure is moving data from File_In to File_Out + -- with compression or decompression, depend on initialization of + -- Filter parameter. + + ------------------- + -- Compare_Files -- + ------------------- + + procedure Compare_Files (Left, Right : String) is + Left_File, Right_File : File_Type; + begin + Open (Left_File, In_File, Left); + Open (Right_File, In_File, Right); + Compare_Streams (Stream (Left_File).all, Stream (Right_File).all); + Close (Left_File); + Close (Right_File); + end Compare_Files; + + --------------------- + -- Compare_Streams -- + --------------------- + + procedure Compare_Streams + (Left, Right : in out Ada.Streams.Root_Stream_Type'Class) + is + Left_Buffer, Right_Buffer : Stream_Element_Array (0 .. 16#FFF#); + Left_Last, Right_Last : Stream_Element_Offset; + begin + loop + Read (Left, Left_Buffer, Left_Last); + Read (Right, Right_Buffer, Right_Last); + + if Left_Last /= Right_Last then + Ada.Text_IO.Put_Line ("Compare error :" + & Stream_Element_Offset'Image (Left_Last) + & " /= " + & Stream_Element_Offset'Image (Right_Last)); + + raise Constraint_Error; + + elsif Left_Buffer (0 .. Left_Last) + /= Right_Buffer (0 .. Right_Last) + then + Ada.Text_IO.Put_Line ("ERROR: IN and OUT files is not equal."); + raise Constraint_Error; + + end if; + + exit when Left_Last < Left_Buffer'Last; + end loop; + end Compare_Streams; + + ------------------ + -- Copy_Streams -- + ------------------ + + procedure Copy_Streams + (Source, Target : in out Ada.Streams.Root_Stream_Type'Class; + Buffer_Size : in Stream_Element_Offset := 1024) + is + Buffer : Stream_Element_Array (1 .. Buffer_Size); + Last : Stream_Element_Offset; + begin + loop + Read (Source, Buffer, Last); + Write (Target, Buffer (1 .. Last)); + + exit when Last < Buffer'Last; + end loop; + end Copy_Streams; + + ------------- + -- Data_In -- + ------------- + + procedure Data_In + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) is + begin + Read (File_In, Item, Last); + end Data_In; + + -------------- + -- Data_Out -- + -------------- + + procedure Data_Out (Item : in Stream_Element_Array) is + begin + Write (File_Out, Item); + end Data_Out; + + ------------------- + -- Generate_File -- + ------------------- + + procedure Generate_File is + subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#; + + package Random_Elements is + new Ada.Numerics.Discrete_Random (Visible_Symbols); + + Gen : Random_Elements.Generator; + Buffer : Stream_Element_Array := (1 .. 77 => 16#20#) & 10; + + Buffer_Count : constant Count := File_Size / Buffer'Length; + -- Number of same buffers in the packet. + + Density : constant Count := 30; -- from 0 to Buffer'Length - 2; + + procedure Fill_Buffer (J, D : in Count); + -- Change the part of the buffer. + + ----------------- + -- Fill_Buffer -- + ----------------- + + procedure Fill_Buffer (J, D : in Count) is + begin + for K in 0 .. D loop + Buffer + (Stream_Element_Offset ((J + K) mod (Buffer'Length - 1) + 1)) + := Random_Elements.Random (Gen); + + end loop; + end Fill_Buffer; + + begin + Random_Elements.Reset (Gen, Init_Random); + + Create (File_In, Out_File, In_File_Name); + + Fill_Buffer (1, Buffer'Length - 2); + + for J in 1 .. Buffer_Count loop + Write (File_In, Buffer); + + Fill_Buffer (J, Density); + end loop; + + -- fill remain size. + + Write + (File_In, + Buffer + (1 .. Stream_Element_Offset + (File_Size - Buffer'Length * Buffer_Count))); + + Flush (File_In); + Close (File_In); + end Generate_File; + + --------------------- + -- Print_Statistic -- + --------------------- + + procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count) is + use Ada.Calendar; + use Ada.Text_IO; + + package Count_IO is new Integer_IO (ZLib.Count); + + Curr_Dur : Duration := Clock - Time_Stamp; + begin + Put (Msg); + + Set_Col (20); + Ada.Text_IO.Put ("size ="); + + Count_IO.Put + (Data_Size, + Width => Stream_IO.Count'Image (File_Size)'Length); + + Put_Line (" duration =" & Duration'Image (Curr_Dur)); + end Print_Statistic; + + ----------- + -- Stamp -- + ----------- + + procedure Stamp is + begin + Time_Stamp := Ada.Calendar.Clock; + end Stamp; + +begin + Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version); + + loop + Generate_File; + + for Level in ZLib.Compression_Level'Range loop + + Ada.Text_IO.Put_Line ("Level =" + & ZLib.Compression_Level'Image (Level)); + + -- Test generic interface. + Open (File_In, In_File, In_File_Name); + Create (File_Out, Out_File, Z_File_Name); + + Stamp; + + -- Deflate using generic instantiation. + + ZLib.Deflate_Init + (Filter => Filter, + Level => Level, + Strategy => Strategy, + Header => Header); + + Translate (Filter); + Print_Statistic ("Generic compress", ZLib.Total_Out (Filter)); + ZLib.Close (Filter); + + Close (File_In); + Close (File_Out); + + Open (File_In, In_File, Z_File_Name); + Create (File_Out, Out_File, Out_File_Name); + + Stamp; + + -- Inflate using generic instantiation. + + ZLib.Inflate_Init (Filter, Header => Header); + + Translate (Filter); + Print_Statistic ("Generic decompress", ZLib.Total_Out (Filter)); + + ZLib.Close (Filter); + + Close (File_In); + Close (File_Out); + + Compare_Files (In_File_Name, Out_File_Name); + + -- Test stream interface. + + -- Compress to the back stream. + + Open (File_In, In_File, In_File_Name); + Create (File_Back, Out_File, Z_File_Name); + + Stamp; + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.Out_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => True, + Level => Level, + Strategy => Strategy, + Header => Header); + + Copy_Streams + (Source => Stream (File_In).all, + Target => File_Z); + + -- Flushing internal buffers to the back stream. + + ZLib.Streams.Flush (File_Z, ZLib.Finish); + + Print_Statistic ("Write compress", + ZLib.Streams.Write_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + + Close (File_In); + Close (File_Back); + + -- Compare reading from original file and from + -- decompression stream. + + Open (File_In, In_File, In_File_Name); + Open (File_Back, In_File, Z_File_Name); + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.In_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => True, + Header => Header); + + Stamp; + Compare_Streams (Stream (File_In).all, File_Z); + + Print_Statistic ("Read decompress", + ZLib.Streams.Read_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + Close (File_In); + Close (File_Back); + + -- Compress by reading from compression stream. + + Open (File_Back, In_File, In_File_Name); + Create (File_Out, Out_File, Z_File_Name); + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.In_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => False, + Level => Level, + Strategy => Strategy, + Header => Header); + + Stamp; + Copy_Streams + (Source => File_Z, + Target => Stream (File_Out).all); + + Print_Statistic ("Read compress", + ZLib.Streams.Read_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + + Close (File_Out); + Close (File_Back); + + -- Decompress to decompression stream. + + Open (File_In, In_File, Z_File_Name); + Create (File_Back, Out_File, Out_File_Name); + + ZLib.Streams.Create + (Stream => File_Z, + Mode => ZLib.Streams.Out_Stream, + Back => ZLib.Streams.Stream_Access + (Stream (File_Back)), + Back_Compressed => False, + Header => Header); + + Stamp; + + Copy_Streams + (Source => Stream (File_In).all, + Target => File_Z); + + Print_Statistic ("Write decompress", + ZLib.Streams.Write_Total_Out (File_Z)); + + ZLib.Streams.Close (File_Z); + Close (File_In); + Close (File_Back); + + Compare_Files (In_File_Name, Out_File_Name); + end loop; + + Ada.Text_IO.Put_Line (Count'Image (File_Size) & " Ok."); + + exit when not Continuous; + + File_Size := File_Size + 1; + end loop; +end Test; diff --git a/test/zlib/zlib-1.2.8/contrib/ada/zlib-streams.adb b/test/zlib/zlib-1.2.8/contrib/ada/zlib-streams.adb new file mode 100644 index 000000000..b6497bae2 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/ada/zlib-streams.adb @@ -0,0 +1,225 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-streams.adb,v 1.10 2004/05/31 10:53:40 vagul Exp $ + +with Ada.Unchecked_Deallocation; + +package body ZLib.Streams is + + ----------- + -- Close -- + ----------- + + procedure Close (Stream : in out Stream_Type) is + procedure Free is new Ada.Unchecked_Deallocation + (Stream_Element_Array, Buffer_Access); + begin + if Stream.Mode = Out_Stream or Stream.Mode = Duplex then + -- We should flush the data written by the writer. + + Flush (Stream, Finish); + + Close (Stream.Writer); + end if; + + if Stream.Mode = In_Stream or Stream.Mode = Duplex then + Close (Stream.Reader); + Free (Stream.Buffer); + end if; + end Close; + + ------------ + -- Create -- + ------------ + + procedure Create + (Stream : out Stream_Type; + Mode : in Stream_Mode; + Back : in Stream_Access; + Back_Compressed : in Boolean; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Header : in Header_Type := Default; + Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size; + Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size) + is + + subtype Buffer_Subtype is Stream_Element_Array (1 .. Read_Buffer_Size); + + procedure Init_Filter + (Filter : in out Filter_Type; + Compress : in Boolean); + + ----------------- + -- Init_Filter -- + ----------------- + + procedure Init_Filter + (Filter : in out Filter_Type; + Compress : in Boolean) is + begin + if Compress then + Deflate_Init + (Filter, Level, Strategy, Header => Header); + else + Inflate_Init (Filter, Header => Header); + end if; + end Init_Filter; + + begin + Stream.Back := Back; + Stream.Mode := Mode; + + if Mode = Out_Stream or Mode = Duplex then + Init_Filter (Stream.Writer, Back_Compressed); + Stream.Buffer_Size := Write_Buffer_Size; + else + Stream.Buffer_Size := 0; + end if; + + if Mode = In_Stream or Mode = Duplex then + Init_Filter (Stream.Reader, not Back_Compressed); + + Stream.Buffer := new Buffer_Subtype; + Stream.Rest_First := Stream.Buffer'Last + 1; + Stream.Rest_Last := Stream.Buffer'Last; + end if; + end Create; + + ----------- + -- Flush -- + ----------- + + procedure Flush + (Stream : in out Stream_Type; + Mode : in Flush_Mode := Sync_Flush) + is + Buffer : Stream_Element_Array (1 .. Stream.Buffer_Size); + Last : Stream_Element_Offset; + begin + loop + Flush (Stream.Writer, Buffer, Last, Mode); + + Ada.Streams.Write (Stream.Back.all, Buffer (1 .. Last)); + + exit when Last < Buffer'Last; + end loop; + end Flush; + + ------------- + -- Is_Open -- + ------------- + + function Is_Open (Stream : Stream_Type) return Boolean is + begin + return Is_Open (Stream.Reader) or else Is_Open (Stream.Writer); + end Is_Open; + + ---------- + -- Read -- + ---------- + + procedure Read + (Stream : in out Stream_Type; + Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) + is + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset); + + ---------- + -- Read -- + ---------- + + procedure Read + (Item : out Stream_Element_Array; + Last : out Stream_Element_Offset) is + begin + Ada.Streams.Read (Stream.Back.all, Item, Last); + end Read; + + procedure Read is new ZLib.Read + (Read => Read, + Buffer => Stream.Buffer.all, + Rest_First => Stream.Rest_First, + Rest_Last => Stream.Rest_Last); + + begin + Read (Stream.Reader, Item, Last); + end Read; + + ------------------- + -- Read_Total_In -- + ------------------- + + function Read_Total_In (Stream : in Stream_Type) return Count is + begin + return Total_In (Stream.Reader); + end Read_Total_In; + + -------------------- + -- Read_Total_Out -- + -------------------- + + function Read_Total_Out (Stream : in Stream_Type) return Count is + begin + return Total_Out (Stream.Reader); + end Read_Total_Out; + + ----------- + -- Write -- + ----------- + + procedure Write + (Stream : in out Stream_Type; + Item : in Stream_Element_Array) + is + + procedure Write (Item : in Stream_Element_Array); + + ----------- + -- Write -- + ----------- + + procedure Write (Item : in Stream_Element_Array) is + begin + Ada.Streams.Write (Stream.Back.all, Item); + end Write; + + procedure Write is new ZLib.Write + (Write => Write, + Buffer_Size => Stream.Buffer_Size); + + begin + Write (Stream.Writer, Item, No_Flush); + end Write; + + -------------------- + -- Write_Total_In -- + -------------------- + + function Write_Total_In (Stream : in Stream_Type) return Count is + begin + return Total_In (Stream.Writer); + end Write_Total_In; + + --------------------- + -- Write_Total_Out -- + --------------------- + + function Write_Total_Out (Stream : in Stream_Type) return Count is + begin + return Total_Out (Stream.Writer); + end Write_Total_Out; + +end ZLib.Streams; diff --git a/test/zlib/zlib-1.2.8/contrib/ada/zlib-streams.ads b/test/zlib/zlib-1.2.8/contrib/ada/zlib-streams.ads new file mode 100644 index 000000000..f0193c6ba --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/ada/zlib-streams.ads @@ -0,0 +1,114 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-streams.ads,v 1.12 2004/05/31 10:53:40 vagul Exp $ + +package ZLib.Streams is + + type Stream_Mode is (In_Stream, Out_Stream, Duplex); + + type Stream_Access is access all Ada.Streams.Root_Stream_Type'Class; + + type Stream_Type is + new Ada.Streams.Root_Stream_Type with private; + + procedure Read + (Stream : in out Stream_Type; + Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + + procedure Write + (Stream : in out Stream_Type; + Item : in Ada.Streams.Stream_Element_Array); + + procedure Flush + (Stream : in out Stream_Type; + Mode : in Flush_Mode := Sync_Flush); + -- Flush the written data to the back stream, + -- all data placed to the compressor is flushing to the Back stream. + -- Should not be used untill necessary, becouse it is decreasing + -- compression. + + function Read_Total_In (Stream : in Stream_Type) return Count; + pragma Inline (Read_Total_In); + -- Return total number of bytes read from back stream so far. + + function Read_Total_Out (Stream : in Stream_Type) return Count; + pragma Inline (Read_Total_Out); + -- Return total number of bytes read so far. + + function Write_Total_In (Stream : in Stream_Type) return Count; + pragma Inline (Write_Total_In); + -- Return total number of bytes written so far. + + function Write_Total_Out (Stream : in Stream_Type) return Count; + pragma Inline (Write_Total_Out); + -- Return total number of bytes written to the back stream. + + procedure Create + (Stream : out Stream_Type; + Mode : in Stream_Mode; + Back : in Stream_Access; + Back_Compressed : in Boolean; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Header : in Header_Type := Default; + Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size; + Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size); + -- Create the Comression/Decompression stream. + -- If mode is In_Stream then Write operation is disabled. + -- If mode is Out_Stream then Read operation is disabled. + + -- If Back_Compressed is true then + -- Data written to the Stream is compressing to the Back stream + -- and data read from the Stream is decompressed data from the Back stream. + + -- If Back_Compressed is false then + -- Data written to the Stream is decompressing to the Back stream + -- and data read from the Stream is compressed data from the Back stream. + + -- !!! When the Need_Header is False ZLib-Ada is using undocumented + -- ZLib 1.1.4 functionality to do not create/wait for ZLib headers. + + function Is_Open (Stream : Stream_Type) return Boolean; + + procedure Close (Stream : in out Stream_Type); + +private + + use Ada.Streams; + + type Buffer_Access is access all Stream_Element_Array; + + type Stream_Type + is new Root_Stream_Type with + record + Mode : Stream_Mode; + + Buffer : Buffer_Access; + Rest_First : Stream_Element_Offset; + Rest_Last : Stream_Element_Offset; + -- Buffer for Read operation. + -- We need to have this buffer in the record + -- becouse not all read data from back stream + -- could be processed during the read operation. + + Buffer_Size : Stream_Element_Offset; + -- Buffer size for write operation. + -- We do not need to have this buffer + -- in the record becouse all data could be + -- processed in the write operation. + + Back : Stream_Access; + Reader : Filter_Type; + Writer : Filter_Type; + end record; + +end ZLib.Streams; diff --git a/test/zlib/zlib-1.2.8/contrib/ada/zlib-thin.adb b/test/zlib/zlib-1.2.8/contrib/ada/zlib-thin.adb new file mode 100644 index 000000000..0ca4a7120 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/ada/zlib-thin.adb @@ -0,0 +1,141 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-thin.adb,v 1.8 2003/12/14 18:27:31 vagul Exp $ + +package body ZLib.Thin is + + ZLIB_VERSION : constant Chars_Ptr := zlibVersion; + + Z_Stream_Size : constant Int := Z_Stream'Size / System.Storage_Unit; + + -------------- + -- Avail_In -- + -------------- + + function Avail_In (Strm : in Z_Stream) return UInt is + begin + return Strm.Avail_In; + end Avail_In; + + --------------- + -- Avail_Out -- + --------------- + + function Avail_Out (Strm : in Z_Stream) return UInt is + begin + return Strm.Avail_Out; + end Avail_Out; + + ------------------ + -- Deflate_Init -- + ------------------ + + function Deflate_Init + (strm : Z_Streamp; + level : Int; + method : Int; + windowBits : Int; + memLevel : Int; + strategy : Int) + return Int is + begin + return deflateInit2 + (strm, + level, + method, + windowBits, + memLevel, + strategy, + ZLIB_VERSION, + Z_Stream_Size); + end Deflate_Init; + + ------------------ + -- Inflate_Init -- + ------------------ + + function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int is + begin + return inflateInit2 (strm, windowBits, ZLIB_VERSION, Z_Stream_Size); + end Inflate_Init; + + ------------------------ + -- Last_Error_Message -- + ------------------------ + + function Last_Error_Message (Strm : in Z_Stream) return String is + use Interfaces.C.Strings; + begin + if Strm.msg = Null_Ptr then + return ""; + else + return Value (Strm.msg); + end if; + end Last_Error_Message; + + ------------ + -- Set_In -- + ------------ + + procedure Set_In + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt) is + begin + Strm.Next_In := Buffer; + Strm.Avail_In := Size; + end Set_In; + + ------------------ + -- Set_Mem_Func -- + ------------------ + + procedure Set_Mem_Func + (Strm : in out Z_Stream; + Opaque : in Voidp; + Alloc : in alloc_func; + Free : in free_func) is + begin + Strm.opaque := Opaque; + Strm.zalloc := Alloc; + Strm.zfree := Free; + end Set_Mem_Func; + + ------------- + -- Set_Out -- + ------------- + + procedure Set_Out + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt) is + begin + Strm.Next_Out := Buffer; + Strm.Avail_Out := Size; + end Set_Out; + + -------------- + -- Total_In -- + -------------- + + function Total_In (Strm : in Z_Stream) return ULong is + begin + return Strm.Total_In; + end Total_In; + + --------------- + -- Total_Out -- + --------------- + + function Total_Out (Strm : in Z_Stream) return ULong is + begin + return Strm.Total_Out; + end Total_Out; + +end ZLib.Thin; diff --git a/test/zlib/zlib-1.2.8/contrib/ada/zlib-thin.ads b/test/zlib/zlib-1.2.8/contrib/ada/zlib-thin.ads new file mode 100644 index 000000000..d4407eb80 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/ada/zlib-thin.ads @@ -0,0 +1,450 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2003 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib-thin.ads,v 1.11 2004/07/23 06:33:11 vagul Exp $ + +with Interfaces.C.Strings; + +with System; + +private package ZLib.Thin is + + -- From zconf.h + + MAX_MEM_LEVEL : constant := 9; -- zconf.h:105 + -- zconf.h:105 + MAX_WBITS : constant := 15; -- zconf.h:115 + -- 32K LZ77 window + -- zconf.h:115 + SEEK_SET : constant := 8#0000#; -- zconf.h:244 + -- Seek from beginning of file. + -- zconf.h:244 + SEEK_CUR : constant := 1; -- zconf.h:245 + -- Seek from current position. + -- zconf.h:245 + SEEK_END : constant := 2; -- zconf.h:246 + -- Set file pointer to EOF plus "offset" + -- zconf.h:246 + + type Byte is new Interfaces.C.unsigned_char; -- 8 bits + -- zconf.h:214 + type UInt is new Interfaces.C.unsigned; -- 16 bits or more + -- zconf.h:216 + type Int is new Interfaces.C.int; + + type ULong is new Interfaces.C.unsigned_long; -- 32 bits or more + -- zconf.h:217 + subtype Chars_Ptr is Interfaces.C.Strings.chars_ptr; + + type ULong_Access is access ULong; + type Int_Access is access Int; + + subtype Voidp is System.Address; -- zconf.h:232 + + subtype Byte_Access is Voidp; + + Nul : constant Voidp := System.Null_Address; + -- end from zconf + + Z_NO_FLUSH : constant := 8#0000#; -- zlib.h:125 + -- zlib.h:125 + Z_PARTIAL_FLUSH : constant := 1; -- zlib.h:126 + -- will be removed, use + -- Z_SYNC_FLUSH instead + -- zlib.h:126 + Z_SYNC_FLUSH : constant := 2; -- zlib.h:127 + -- zlib.h:127 + Z_FULL_FLUSH : constant := 3; -- zlib.h:128 + -- zlib.h:128 + Z_FINISH : constant := 4; -- zlib.h:129 + -- zlib.h:129 + Z_OK : constant := 8#0000#; -- zlib.h:132 + -- zlib.h:132 + Z_STREAM_END : constant := 1; -- zlib.h:133 + -- zlib.h:133 + Z_NEED_DICT : constant := 2; -- zlib.h:134 + -- zlib.h:134 + Z_ERRNO : constant := -1; -- zlib.h:135 + -- zlib.h:135 + Z_STREAM_ERROR : constant := -2; -- zlib.h:136 + -- zlib.h:136 + Z_DATA_ERROR : constant := -3; -- zlib.h:137 + -- zlib.h:137 + Z_MEM_ERROR : constant := -4; -- zlib.h:138 + -- zlib.h:138 + Z_BUF_ERROR : constant := -5; -- zlib.h:139 + -- zlib.h:139 + Z_VERSION_ERROR : constant := -6; -- zlib.h:140 + -- zlib.h:140 + Z_NO_COMPRESSION : constant := 8#0000#; -- zlib.h:145 + -- zlib.h:145 + Z_BEST_SPEED : constant := 1; -- zlib.h:146 + -- zlib.h:146 + Z_BEST_COMPRESSION : constant := 9; -- zlib.h:147 + -- zlib.h:147 + Z_DEFAULT_COMPRESSION : constant := -1; -- zlib.h:148 + -- zlib.h:148 + Z_FILTERED : constant := 1; -- zlib.h:151 + -- zlib.h:151 + Z_HUFFMAN_ONLY : constant := 2; -- zlib.h:152 + -- zlib.h:152 + Z_DEFAULT_STRATEGY : constant := 8#0000#; -- zlib.h:153 + -- zlib.h:153 + Z_BINARY : constant := 8#0000#; -- zlib.h:156 + -- zlib.h:156 + Z_ASCII : constant := 1; -- zlib.h:157 + -- zlib.h:157 + Z_UNKNOWN : constant := 2; -- zlib.h:158 + -- zlib.h:158 + Z_DEFLATED : constant := 8; -- zlib.h:161 + -- zlib.h:161 + Z_NULL : constant := 8#0000#; -- zlib.h:164 + -- for initializing zalloc, zfree, opaque + -- zlib.h:164 + type gzFile is new Voidp; -- zlib.h:646 + + type Z_Stream is private; + + type Z_Streamp is access all Z_Stream; -- zlib.h:89 + + type alloc_func is access function + (Opaque : Voidp; + Items : UInt; + Size : UInt) + return Voidp; -- zlib.h:63 + + type free_func is access procedure (opaque : Voidp; address : Voidp); + + function zlibVersion return Chars_Ptr; + + function Deflate (strm : Z_Streamp; flush : Int) return Int; + + function DeflateEnd (strm : Z_Streamp) return Int; + + function Inflate (strm : Z_Streamp; flush : Int) return Int; + + function InflateEnd (strm : Z_Streamp) return Int; + + function deflateSetDictionary + (strm : Z_Streamp; + dictionary : Byte_Access; + dictLength : UInt) + return Int; + + function deflateCopy (dest : Z_Streamp; source : Z_Streamp) return Int; + -- zlib.h:478 + + function deflateReset (strm : Z_Streamp) return Int; -- zlib.h:495 + + function deflateParams + (strm : Z_Streamp; + level : Int; + strategy : Int) + return Int; -- zlib.h:506 + + function inflateSetDictionary + (strm : Z_Streamp; + dictionary : Byte_Access; + dictLength : UInt) + return Int; -- zlib.h:548 + + function inflateSync (strm : Z_Streamp) return Int; -- zlib.h:565 + + function inflateReset (strm : Z_Streamp) return Int; -- zlib.h:580 + + function compress + (dest : Byte_Access; + destLen : ULong_Access; + source : Byte_Access; + sourceLen : ULong) + return Int; -- zlib.h:601 + + function compress2 + (dest : Byte_Access; + destLen : ULong_Access; + source : Byte_Access; + sourceLen : ULong; + level : Int) + return Int; -- zlib.h:615 + + function uncompress + (dest : Byte_Access; + destLen : ULong_Access; + source : Byte_Access; + sourceLen : ULong) + return Int; + + function gzopen (path : Chars_Ptr; mode : Chars_Ptr) return gzFile; + + function gzdopen (fd : Int; mode : Chars_Ptr) return gzFile; + + function gzsetparams + (file : gzFile; + level : Int; + strategy : Int) + return Int; + + function gzread + (file : gzFile; + buf : Voidp; + len : UInt) + return Int; + + function gzwrite + (file : in gzFile; + buf : in Voidp; + len : in UInt) + return Int; + + function gzprintf (file : in gzFile; format : in Chars_Ptr) return Int; + + function gzputs (file : in gzFile; s : in Chars_Ptr) return Int; + + function gzgets + (file : gzFile; + buf : Chars_Ptr; + len : Int) + return Chars_Ptr; + + function gzputc (file : gzFile; char : Int) return Int; + + function gzgetc (file : gzFile) return Int; + + function gzflush (file : gzFile; flush : Int) return Int; + + function gzseek + (file : gzFile; + offset : Int; + whence : Int) + return Int; + + function gzrewind (file : gzFile) return Int; + + function gztell (file : gzFile) return Int; + + function gzeof (file : gzFile) return Int; + + function gzclose (file : gzFile) return Int; + + function gzerror (file : gzFile; errnum : Int_Access) return Chars_Ptr; + + function adler32 + (adler : ULong; + buf : Byte_Access; + len : UInt) + return ULong; + + function crc32 + (crc : ULong; + buf : Byte_Access; + len : UInt) + return ULong; + + function deflateInit + (strm : Z_Streamp; + level : Int; + version : Chars_Ptr; + stream_size : Int) + return Int; + + function deflateInit2 + (strm : Z_Streamp; + level : Int; + method : Int; + windowBits : Int; + memLevel : Int; + strategy : Int; + version : Chars_Ptr; + stream_size : Int) + return Int; + + function Deflate_Init + (strm : Z_Streamp; + level : Int; + method : Int; + windowBits : Int; + memLevel : Int; + strategy : Int) + return Int; + pragma Inline (Deflate_Init); + + function inflateInit + (strm : Z_Streamp; + version : Chars_Ptr; + stream_size : Int) + return Int; + + function inflateInit2 + (strm : in Z_Streamp; + windowBits : in Int; + version : in Chars_Ptr; + stream_size : in Int) + return Int; + + function inflateBackInit + (strm : in Z_Streamp; + windowBits : in Int; + window : in Byte_Access; + version : in Chars_Ptr; + stream_size : in Int) + return Int; + -- Size of window have to be 2**windowBits. + + function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int; + pragma Inline (Inflate_Init); + + function zError (err : Int) return Chars_Ptr; + + function inflateSyncPoint (z : Z_Streamp) return Int; + + function get_crc_table return ULong_Access; + + -- Interface to the available fields of the z_stream structure. + -- The application must update next_in and avail_in when avail_in has + -- dropped to zero. It must update next_out and avail_out when avail_out + -- has dropped to zero. The application must initialize zalloc, zfree and + -- opaque before calling the init function. + + procedure Set_In + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt); + pragma Inline (Set_In); + + procedure Set_Out + (Strm : in out Z_Stream; + Buffer : in Voidp; + Size : in UInt); + pragma Inline (Set_Out); + + procedure Set_Mem_Func + (Strm : in out Z_Stream; + Opaque : in Voidp; + Alloc : in alloc_func; + Free : in free_func); + pragma Inline (Set_Mem_Func); + + function Last_Error_Message (Strm : in Z_Stream) return String; + pragma Inline (Last_Error_Message); + + function Avail_Out (Strm : in Z_Stream) return UInt; + pragma Inline (Avail_Out); + + function Avail_In (Strm : in Z_Stream) return UInt; + pragma Inline (Avail_In); + + function Total_In (Strm : in Z_Stream) return ULong; + pragma Inline (Total_In); + + function Total_Out (Strm : in Z_Stream) return ULong; + pragma Inline (Total_Out); + + function inflateCopy + (dest : in Z_Streamp; + Source : in Z_Streamp) + return Int; + + function compressBound (Source_Len : in ULong) return ULong; + + function deflateBound + (Strm : in Z_Streamp; + Source_Len : in ULong) + return ULong; + + function gzungetc (C : in Int; File : in gzFile) return Int; + + function zlibCompileFlags return ULong; + +private + + type Z_Stream is record -- zlib.h:68 + Next_In : Voidp := Nul; -- next input byte + Avail_In : UInt := 0; -- number of bytes available at next_in + Total_In : ULong := 0; -- total nb of input bytes read so far + Next_Out : Voidp := Nul; -- next output byte should be put there + Avail_Out : UInt := 0; -- remaining free space at next_out + Total_Out : ULong := 0; -- total nb of bytes output so far + msg : Chars_Ptr; -- last error message, NULL if no error + state : Voidp; -- not visible by applications + zalloc : alloc_func := null; -- used to allocate the internal state + zfree : free_func := null; -- used to free the internal state + opaque : Voidp; -- private data object passed to + -- zalloc and zfree + data_type : Int; -- best guess about the data type: + -- ascii or binary + adler : ULong; -- adler32 value of the uncompressed + -- data + reserved : ULong; -- reserved for future use + end record; + + pragma Convention (C, Z_Stream); + + pragma Import (C, zlibVersion, "zlibVersion"); + pragma Import (C, Deflate, "deflate"); + pragma Import (C, DeflateEnd, "deflateEnd"); + pragma Import (C, Inflate, "inflate"); + pragma Import (C, InflateEnd, "inflateEnd"); + pragma Import (C, deflateSetDictionary, "deflateSetDictionary"); + pragma Import (C, deflateCopy, "deflateCopy"); + pragma Import (C, deflateReset, "deflateReset"); + pragma Import (C, deflateParams, "deflateParams"); + pragma Import (C, inflateSetDictionary, "inflateSetDictionary"); + pragma Import (C, inflateSync, "inflateSync"); + pragma Import (C, inflateReset, "inflateReset"); + pragma Import (C, compress, "compress"); + pragma Import (C, compress2, "compress2"); + pragma Import (C, uncompress, "uncompress"); + pragma Import (C, gzopen, "gzopen"); + pragma Import (C, gzdopen, "gzdopen"); + pragma Import (C, gzsetparams, "gzsetparams"); + pragma Import (C, gzread, "gzread"); + pragma Import (C, gzwrite, "gzwrite"); + pragma Import (C, gzprintf, "gzprintf"); + pragma Import (C, gzputs, "gzputs"); + pragma Import (C, gzgets, "gzgets"); + pragma Import (C, gzputc, "gzputc"); + pragma Import (C, gzgetc, "gzgetc"); + pragma Import (C, gzflush, "gzflush"); + pragma Import (C, gzseek, "gzseek"); + pragma Import (C, gzrewind, "gzrewind"); + pragma Import (C, gztell, "gztell"); + pragma Import (C, gzeof, "gzeof"); + pragma Import (C, gzclose, "gzclose"); + pragma Import (C, gzerror, "gzerror"); + pragma Import (C, adler32, "adler32"); + pragma Import (C, crc32, "crc32"); + pragma Import (C, deflateInit, "deflateInit_"); + pragma Import (C, inflateInit, "inflateInit_"); + pragma Import (C, deflateInit2, "deflateInit2_"); + pragma Import (C, inflateInit2, "inflateInit2_"); + pragma Import (C, zError, "zError"); + pragma Import (C, inflateSyncPoint, "inflateSyncPoint"); + pragma Import (C, get_crc_table, "get_crc_table"); + + -- since zlib 1.2.0: + + pragma Import (C, inflateCopy, "inflateCopy"); + pragma Import (C, compressBound, "compressBound"); + pragma Import (C, deflateBound, "deflateBound"); + pragma Import (C, gzungetc, "gzungetc"); + pragma Import (C, zlibCompileFlags, "zlibCompileFlags"); + + pragma Import (C, inflateBackInit, "inflateBackInit_"); + + -- I stopped binding the inflateBack routines, becouse realize that + -- it does not support zlib and gzip headers for now, and have no + -- symmetric deflateBack routines. + -- ZLib-Ada is symmetric regarding deflate/inflate data transformation + -- and has a similar generic callback interface for the + -- deflate/inflate transformation based on the regular Deflate/Inflate + -- routines. + + -- pragma Import (C, inflateBack, "inflateBack"); + -- pragma Import (C, inflateBackEnd, "inflateBackEnd"); + +end ZLib.Thin; diff --git a/test/zlib/zlib-1.2.8/contrib/ada/zlib.adb b/test/zlib/zlib-1.2.8/contrib/ada/zlib.adb new file mode 100644 index 000000000..8b6fd686a --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/ada/zlib.adb @@ -0,0 +1,701 @@ +---------------------------------------------------------------- +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2004 Dmitriy Anisimkov -- +-- -- +-- Open source license information is in the zlib.ads file. -- +---------------------------------------------------------------- + +-- $Id: zlib.adb,v 1.31 2004/09/06 06:53:19 vagul Exp $ + +with Ada.Exceptions; +with Ada.Unchecked_Conversion; +with Ada.Unchecked_Deallocation; + +with Interfaces.C.Strings; + +with ZLib.Thin; + +package body ZLib is + + use type Thin.Int; + + type Z_Stream is new Thin.Z_Stream; + + type Return_Code_Enum is + (OK, + STREAM_END, + NEED_DICT, + ERRNO, + STREAM_ERROR, + DATA_ERROR, + MEM_ERROR, + BUF_ERROR, + VERSION_ERROR); + + type Flate_Step_Function is access + function (Strm : in Thin.Z_Streamp; Flush : in Thin.Int) return Thin.Int; + pragma Convention (C, Flate_Step_Function); + + type Flate_End_Function is access + function (Ctrm : in Thin.Z_Streamp) return Thin.Int; + pragma Convention (C, Flate_End_Function); + + type Flate_Type is record + Step : Flate_Step_Function; + Done : Flate_End_Function; + end record; + + subtype Footer_Array is Stream_Element_Array (1 .. 8); + + Simple_GZip_Header : constant Stream_Element_Array (1 .. 10) + := (16#1f#, 16#8b#, -- Magic header + 16#08#, -- Z_DEFLATED + 16#00#, -- Flags + 16#00#, 16#00#, 16#00#, 16#00#, -- Time + 16#00#, -- XFlags + 16#03# -- OS code + ); + -- The simplest gzip header is not for informational, but just for + -- gzip format compatibility. + -- Note that some code below is using assumption + -- Simple_GZip_Header'Last > Footer_Array'Last, so do not make + -- Simple_GZip_Header'Last <= Footer_Array'Last. + + Return_Code : constant array (Thin.Int range <>) of Return_Code_Enum + := (0 => OK, + 1 => STREAM_END, + 2 => NEED_DICT, + -1 => ERRNO, + -2 => STREAM_ERROR, + -3 => DATA_ERROR, + -4 => MEM_ERROR, + -5 => BUF_ERROR, + -6 => VERSION_ERROR); + + Flate : constant array (Boolean) of Flate_Type + := (True => (Step => Thin.Deflate'Access, + Done => Thin.DeflateEnd'Access), + False => (Step => Thin.Inflate'Access, + Done => Thin.InflateEnd'Access)); + + Flush_Finish : constant array (Boolean) of Flush_Mode + := (True => Finish, False => No_Flush); + + procedure Raise_Error (Stream : in Z_Stream); + pragma Inline (Raise_Error); + + procedure Raise_Error (Message : in String); + pragma Inline (Raise_Error); + + procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int); + + procedure Free is new Ada.Unchecked_Deallocation + (Z_Stream, Z_Stream_Access); + + function To_Thin_Access is new Ada.Unchecked_Conversion + (Z_Stream_Access, Thin.Z_Streamp); + + procedure Translate_GZip + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + -- Separate translate routine for make gzip header. + + procedure Translate_Auto + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + -- translate routine without additional headers. + + ----------------- + -- Check_Error -- + ----------------- + + procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int) is + use type Thin.Int; + begin + if Code /= Thin.Z_OK then + Raise_Error + (Return_Code_Enum'Image (Return_Code (Code)) + & ": " & Last_Error_Message (Stream)); + end if; + end Check_Error; + + ----------- + -- Close -- + ----------- + + procedure Close + (Filter : in out Filter_Type; + Ignore_Error : in Boolean := False) + is + Code : Thin.Int; + begin + if not Ignore_Error and then not Is_Open (Filter) then + raise Status_Error; + end if; + + Code := Flate (Filter.Compression).Done (To_Thin_Access (Filter.Strm)); + + if Ignore_Error or else Code = Thin.Z_OK then + Free (Filter.Strm); + else + declare + Error_Message : constant String + := Last_Error_Message (Filter.Strm.all); + begin + Free (Filter.Strm); + Ada.Exceptions.Raise_Exception + (ZLib_Error'Identity, + Return_Code_Enum'Image (Return_Code (Code)) + & ": " & Error_Message); + end; + end if; + end Close; + + ----------- + -- CRC32 -- + ----------- + + function CRC32 + (CRC : in Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array) + return Unsigned_32 + is + use Thin; + begin + return Unsigned_32 (crc32 (ULong (CRC), + Data'Address, + Data'Length)); + end CRC32; + + procedure CRC32 + (CRC : in out Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array) is + begin + CRC := CRC32 (CRC, Data); + end CRC32; + + ------------------ + -- Deflate_Init -- + ------------------ + + procedure Deflate_Init + (Filter : in out Filter_Type; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Method : in Compression_Method := Deflated; + Window_Bits : in Window_Bits_Type := Default_Window_Bits; + Memory_Level : in Memory_Level_Type := Default_Memory_Level; + Header : in Header_Type := Default) + is + use type Thin.Int; + Win_Bits : Thin.Int := Thin.Int (Window_Bits); + begin + if Is_Open (Filter) then + raise Status_Error; + end if; + + -- We allow ZLib to make header only in case of default header type. + -- Otherwise we would either do header by ourselfs, or do not do + -- header at all. + + if Header = None or else Header = GZip then + Win_Bits := -Win_Bits; + end if; + + -- For the GZip CRC calculation and make headers. + + if Header = GZip then + Filter.CRC := 0; + Filter.Offset := Simple_GZip_Header'First; + else + Filter.Offset := Simple_GZip_Header'Last + 1; + end if; + + Filter.Strm := new Z_Stream; + Filter.Compression := True; + Filter.Stream_End := False; + Filter.Header := Header; + + if Thin.Deflate_Init + (To_Thin_Access (Filter.Strm), + Level => Thin.Int (Level), + method => Thin.Int (Method), + windowBits => Win_Bits, + memLevel => Thin.Int (Memory_Level), + strategy => Thin.Int (Strategy)) /= Thin.Z_OK + then + Raise_Error (Filter.Strm.all); + end if; + end Deflate_Init; + + ----------- + -- Flush -- + ----------- + + procedure Flush + (Filter : in out Filter_Type; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) + is + No_Data : Stream_Element_Array := (1 .. 0 => 0); + Last : Stream_Element_Offset; + begin + Translate (Filter, No_Data, Last, Out_Data, Out_Last, Flush); + end Flush; + + ----------------------- + -- Generic_Translate -- + ----------------------- + + procedure Generic_Translate + (Filter : in out ZLib.Filter_Type; + In_Buffer_Size : in Integer := Default_Buffer_Size; + Out_Buffer_Size : in Integer := Default_Buffer_Size) + is + In_Buffer : Stream_Element_Array + (1 .. Stream_Element_Offset (In_Buffer_Size)); + Out_Buffer : Stream_Element_Array + (1 .. Stream_Element_Offset (Out_Buffer_Size)); + Last : Stream_Element_Offset; + In_Last : Stream_Element_Offset; + In_First : Stream_Element_Offset; + Out_Last : Stream_Element_Offset; + begin + Main : loop + Data_In (In_Buffer, Last); + + In_First := In_Buffer'First; + + loop + Translate + (Filter => Filter, + In_Data => In_Buffer (In_First .. Last), + In_Last => In_Last, + Out_Data => Out_Buffer, + Out_Last => Out_Last, + Flush => Flush_Finish (Last < In_Buffer'First)); + + if Out_Buffer'First <= Out_Last then + Data_Out (Out_Buffer (Out_Buffer'First .. Out_Last)); + end if; + + exit Main when Stream_End (Filter); + + -- The end of in buffer. + + exit when In_Last = Last; + + In_First := In_Last + 1; + end loop; + end loop Main; + + end Generic_Translate; + + ------------------ + -- Inflate_Init -- + ------------------ + + procedure Inflate_Init + (Filter : in out Filter_Type; + Window_Bits : in Window_Bits_Type := Default_Window_Bits; + Header : in Header_Type := Default) + is + use type Thin.Int; + Win_Bits : Thin.Int := Thin.Int (Window_Bits); + + procedure Check_Version; + -- Check the latest header types compatibility. + + procedure Check_Version is + begin + if Version <= "1.1.4" then + Raise_Error + ("Inflate header type " & Header_Type'Image (Header) + & " incompatible with ZLib version " & Version); + end if; + end Check_Version; + + begin + if Is_Open (Filter) then + raise Status_Error; + end if; + + case Header is + when None => + Check_Version; + + -- Inflate data without headers determined + -- by negative Win_Bits. + + Win_Bits := -Win_Bits; + when GZip => + Check_Version; + + -- Inflate gzip data defined by flag 16. + + Win_Bits := Win_Bits + 16; + when Auto => + Check_Version; + + -- Inflate with automatic detection + -- of gzip or native header defined by flag 32. + + Win_Bits := Win_Bits + 32; + when Default => null; + end case; + + Filter.Strm := new Z_Stream; + Filter.Compression := False; + Filter.Stream_End := False; + Filter.Header := Header; + + if Thin.Inflate_Init + (To_Thin_Access (Filter.Strm), Win_Bits) /= Thin.Z_OK + then + Raise_Error (Filter.Strm.all); + end if; + end Inflate_Init; + + ------------- + -- Is_Open -- + ------------- + + function Is_Open (Filter : in Filter_Type) return Boolean is + begin + return Filter.Strm /= null; + end Is_Open; + + ----------------- + -- Raise_Error -- + ----------------- + + procedure Raise_Error (Message : in String) is + begin + Ada.Exceptions.Raise_Exception (ZLib_Error'Identity, Message); + end Raise_Error; + + procedure Raise_Error (Stream : in Z_Stream) is + begin + Raise_Error (Last_Error_Message (Stream)); + end Raise_Error; + + ---------- + -- Read -- + ---------- + + procedure Read + (Filter : in out Filter_Type; + Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode := No_Flush) + is + In_Last : Stream_Element_Offset; + Item_First : Ada.Streams.Stream_Element_Offset := Item'First; + V_Flush : Flush_Mode := Flush; + + begin + pragma Assert (Rest_First in Buffer'First .. Buffer'Last + 1); + pragma Assert (Rest_Last in Buffer'First - 1 .. Buffer'Last); + + loop + if Rest_Last = Buffer'First - 1 then + V_Flush := Finish; + + elsif Rest_First > Rest_Last then + Read (Buffer, Rest_Last); + Rest_First := Buffer'First; + + if Rest_Last < Buffer'First then + V_Flush := Finish; + end if; + end if; + + Translate + (Filter => Filter, + In_Data => Buffer (Rest_First .. Rest_Last), + In_Last => In_Last, + Out_Data => Item (Item_First .. Item'Last), + Out_Last => Last, + Flush => V_Flush); + + Rest_First := In_Last + 1; + + exit when Stream_End (Filter) + or else Last = Item'Last + or else (Last >= Item'First and then Allow_Read_Some); + + Item_First := Last + 1; + end loop; + end Read; + + ---------------- + -- Stream_End -- + ---------------- + + function Stream_End (Filter : in Filter_Type) return Boolean is + begin + if Filter.Header = GZip and Filter.Compression then + return Filter.Stream_End + and then Filter.Offset = Footer_Array'Last + 1; + else + return Filter.Stream_End; + end if; + end Stream_End; + + -------------- + -- Total_In -- + -------------- + + function Total_In (Filter : in Filter_Type) return Count is + begin + return Count (Thin.Total_In (To_Thin_Access (Filter.Strm).all)); + end Total_In; + + --------------- + -- Total_Out -- + --------------- + + function Total_Out (Filter : in Filter_Type) return Count is + begin + return Count (Thin.Total_Out (To_Thin_Access (Filter.Strm).all)); + end Total_Out; + + --------------- + -- Translate -- + --------------- + + procedure Translate + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) is + begin + if Filter.Header = GZip and then Filter.Compression then + Translate_GZip + (Filter => Filter, + In_Data => In_Data, + In_Last => In_Last, + Out_Data => Out_Data, + Out_Last => Out_Last, + Flush => Flush); + else + Translate_Auto + (Filter => Filter, + In_Data => In_Data, + In_Last => In_Last, + Out_Data => Out_Data, + Out_Last => Out_Last, + Flush => Flush); + end if; + end Translate; + + -------------------- + -- Translate_Auto -- + -------------------- + + procedure Translate_Auto + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) + is + use type Thin.Int; + Code : Thin.Int; + + begin + if not Is_Open (Filter) then + raise Status_Error; + end if; + + if Out_Data'Length = 0 and then In_Data'Length = 0 then + raise Constraint_Error; + end if; + + Set_Out (Filter.Strm.all, Out_Data'Address, Out_Data'Length); + Set_In (Filter.Strm.all, In_Data'Address, In_Data'Length); + + Code := Flate (Filter.Compression).Step + (To_Thin_Access (Filter.Strm), + Thin.Int (Flush)); + + if Code = Thin.Z_STREAM_END then + Filter.Stream_End := True; + else + Check_Error (Filter.Strm.all, Code); + end if; + + In_Last := In_Data'Last + - Stream_Element_Offset (Avail_In (Filter.Strm.all)); + Out_Last := Out_Data'Last + - Stream_Element_Offset (Avail_Out (Filter.Strm.all)); + end Translate_Auto; + + -------------------- + -- Translate_GZip -- + -------------------- + + procedure Translate_GZip + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode) + is + Out_First : Stream_Element_Offset; + + procedure Add_Data (Data : in Stream_Element_Array); + -- Add data to stream from the Filter.Offset till necessary, + -- used for add gzip headr/footer. + + procedure Put_32 + (Item : in out Stream_Element_Array; + Data : in Unsigned_32); + pragma Inline (Put_32); + + -------------- + -- Add_Data -- + -------------- + + procedure Add_Data (Data : in Stream_Element_Array) is + Data_First : Stream_Element_Offset renames Filter.Offset; + Data_Last : Stream_Element_Offset; + Data_Len : Stream_Element_Offset; -- -1 + Out_Len : Stream_Element_Offset; -- -1 + begin + Out_First := Out_Last + 1; + + if Data_First > Data'Last then + return; + end if; + + Data_Len := Data'Last - Data_First; + Out_Len := Out_Data'Last - Out_First; + + if Data_Len <= Out_Len then + Out_Last := Out_First + Data_Len; + Data_Last := Data'Last; + else + Out_Last := Out_Data'Last; + Data_Last := Data_First + Out_Len; + end if; + + Out_Data (Out_First .. Out_Last) := Data (Data_First .. Data_Last); + + Data_First := Data_Last + 1; + Out_First := Out_Last + 1; + end Add_Data; + + ------------ + -- Put_32 -- + ------------ + + procedure Put_32 + (Item : in out Stream_Element_Array; + Data : in Unsigned_32) + is + D : Unsigned_32 := Data; + begin + for J in Item'First .. Item'First + 3 loop + Item (J) := Stream_Element (D and 16#FF#); + D := Shift_Right (D, 8); + end loop; + end Put_32; + + begin + Out_Last := Out_Data'First - 1; + + if not Filter.Stream_End then + Add_Data (Simple_GZip_Header); + + Translate_Auto + (Filter => Filter, + In_Data => In_Data, + In_Last => In_Last, + Out_Data => Out_Data (Out_First .. Out_Data'Last), + Out_Last => Out_Last, + Flush => Flush); + + CRC32 (Filter.CRC, In_Data (In_Data'First .. In_Last)); + end if; + + if Filter.Stream_End and then Out_Last <= Out_Data'Last then + -- This detection method would work only when + -- Simple_GZip_Header'Last > Footer_Array'Last + + if Filter.Offset = Simple_GZip_Header'Last + 1 then + Filter.Offset := Footer_Array'First; + end if; + + declare + Footer : Footer_Array; + begin + Put_32 (Footer, Filter.CRC); + Put_32 (Footer (Footer'First + 4 .. Footer'Last), + Unsigned_32 (Total_In (Filter))); + Add_Data (Footer); + end; + end if; + end Translate_GZip; + + ------------- + -- Version -- + ------------- + + function Version return String is + begin + return Interfaces.C.Strings.Value (Thin.zlibVersion); + end Version; + + ----------- + -- Write -- + ----------- + + procedure Write + (Filter : in out Filter_Type; + Item : in Ada.Streams.Stream_Element_Array; + Flush : in Flush_Mode := No_Flush) + is + Buffer : Stream_Element_Array (1 .. Buffer_Size); + In_Last : Stream_Element_Offset; + Out_Last : Stream_Element_Offset; + In_First : Stream_Element_Offset := Item'First; + begin + if Item'Length = 0 and Flush = No_Flush then + return; + end if; + + loop + Translate + (Filter => Filter, + In_Data => Item (In_First .. Item'Last), + In_Last => In_Last, + Out_Data => Buffer, + Out_Last => Out_Last, + Flush => Flush); + + if Out_Last >= Buffer'First then + Write (Buffer (1 .. Out_Last)); + end if; + + exit when In_Last = Item'Last or Stream_End (Filter); + + In_First := In_Last + 1; + end loop; + end Write; + +end ZLib; diff --git a/test/zlib/zlib-1.2.8/contrib/ada/zlib.ads b/test/zlib/zlib-1.2.8/contrib/ada/zlib.ads new file mode 100644 index 000000000..79ffc4095 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/ada/zlib.ads @@ -0,0 +1,328 @@ +------------------------------------------------------------------------------ +-- ZLib for Ada thick binding. -- +-- -- +-- Copyright (C) 2002-2004 Dmitriy Anisimkov -- +-- -- +-- This library is free software; you can redistribute it and/or modify -- +-- it under the terms of the GNU General Public License as published by -- +-- the Free Software Foundation; either version 2 of the License, or (at -- +-- your option) any later version. -- +-- -- +-- This library 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. See the GNU -- +-- General Public License for more details. -- +-- -- +-- You should have received a copy of the GNU General Public License -- +-- along with this library; if not, write to the Free Software Foundation, -- +-- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -- +-- -- +-- As a special exception, if other files instantiate generics from this -- +-- unit, or you link this unit with other files to produce an executable, -- +-- this unit does not by itself cause the resulting executable to be -- +-- covered by the GNU General Public License. This exception does not -- +-- however invalidate any other reasons why the executable file might be -- +-- covered by the GNU Public License. -- +------------------------------------------------------------------------------ + +-- $Id: zlib.ads,v 1.26 2004/09/06 06:53:19 vagul Exp $ + +with Ada.Streams; + +with Interfaces; + +package ZLib is + + ZLib_Error : exception; + Status_Error : exception; + + type Compression_Level is new Integer range -1 .. 9; + + type Flush_Mode is private; + + type Compression_Method is private; + + type Window_Bits_Type is new Integer range 8 .. 15; + + type Memory_Level_Type is new Integer range 1 .. 9; + + type Unsigned_32 is new Interfaces.Unsigned_32; + + type Strategy_Type is private; + + type Header_Type is (None, Auto, Default, GZip); + -- Header type usage have a some limitation for inflate. + -- See comment for Inflate_Init. + + subtype Count is Ada.Streams.Stream_Element_Count; + + Default_Memory_Level : constant Memory_Level_Type := 8; + Default_Window_Bits : constant Window_Bits_Type := 15; + + ---------------------------------- + -- Compression method constants -- + ---------------------------------- + + Deflated : constant Compression_Method; + -- Only one method allowed in this ZLib version + + --------------------------------- + -- Compression level constants -- + --------------------------------- + + No_Compression : constant Compression_Level := 0; + Best_Speed : constant Compression_Level := 1; + Best_Compression : constant Compression_Level := 9; + Default_Compression : constant Compression_Level := -1; + + -------------------------- + -- Flush mode constants -- + -------------------------- + + No_Flush : constant Flush_Mode; + -- Regular way for compression, no flush + + Partial_Flush : constant Flush_Mode; + -- Will be removed, use Z_SYNC_FLUSH instead + + Sync_Flush : constant Flush_Mode; + -- All pending output is flushed to the output buffer and the output + -- is aligned on a byte boundary, so that the decompressor can get all + -- input data available so far. (In particular avail_in is zero after the + -- call if enough output space has been provided before the call.) + -- Flushing may degrade compression for some compression algorithms and so + -- it should be used only when necessary. + + Block_Flush : constant Flush_Mode; + -- Z_BLOCK requests that inflate() stop + -- if and when it get to the next deflate block boundary. When decoding the + -- zlib or gzip format, this will cause inflate() to return immediately + -- after the header and before the first block. When doing a raw inflate, + -- inflate() will go ahead and process the first block, and will return + -- when it gets to the end of that block, or when it runs out of data. + + Full_Flush : constant Flush_Mode; + -- All output is flushed as with SYNC_FLUSH, and the compression state + -- is reset so that decompression can restart from this point if previous + -- compressed data has been damaged or if random access is desired. Using + -- Full_Flush too often can seriously degrade the compression. + + Finish : constant Flush_Mode; + -- Just for tell the compressor that input data is complete. + + ------------------------------------ + -- Compression strategy constants -- + ------------------------------------ + + -- RLE stategy could be used only in version 1.2.0 and later. + + Filtered : constant Strategy_Type; + Huffman_Only : constant Strategy_Type; + RLE : constant Strategy_Type; + Default_Strategy : constant Strategy_Type; + + Default_Buffer_Size : constant := 4096; + + type Filter_Type is tagged limited private; + -- The filter is for compression and for decompression. + -- The usage of the type is depend of its initialization. + + function Version return String; + pragma Inline (Version); + -- Return string representation of the ZLib version. + + procedure Deflate_Init + (Filter : in out Filter_Type; + Level : in Compression_Level := Default_Compression; + Strategy : in Strategy_Type := Default_Strategy; + Method : in Compression_Method := Deflated; + Window_Bits : in Window_Bits_Type := Default_Window_Bits; + Memory_Level : in Memory_Level_Type := Default_Memory_Level; + Header : in Header_Type := Default); + -- Compressor initialization. + -- When Header parameter is Auto or Default, then default zlib header + -- would be provided for compressed data. + -- When Header is GZip, then gzip header would be set instead of + -- default header. + -- When Header is None, no header would be set for compressed data. + + procedure Inflate_Init + (Filter : in out Filter_Type; + Window_Bits : in Window_Bits_Type := Default_Window_Bits; + Header : in Header_Type := Default); + -- Decompressor initialization. + -- Default header type mean that ZLib default header is expecting in the + -- input compressed stream. + -- Header type None mean that no header is expecting in the input stream. + -- GZip header type mean that GZip header is expecting in the + -- input compressed stream. + -- Auto header type mean that header type (GZip or Native) would be + -- detected automatically in the input stream. + -- Note that header types parameter values None, GZip and Auto are + -- supported for inflate routine only in ZLib versions 1.2.0.2 and later. + -- Deflate_Init is supporting all header types. + + function Is_Open (Filter : in Filter_Type) return Boolean; + pragma Inline (Is_Open); + -- Is the filter opened for compression or decompression. + + procedure Close + (Filter : in out Filter_Type; + Ignore_Error : in Boolean := False); + -- Closing the compression or decompressor. + -- If stream is closing before the complete and Ignore_Error is False, + -- The exception would be raised. + + generic + with procedure Data_In + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + with procedure Data_Out + (Item : in Ada.Streams.Stream_Element_Array); + procedure Generic_Translate + (Filter : in out Filter_Type; + In_Buffer_Size : in Integer := Default_Buffer_Size; + Out_Buffer_Size : in Integer := Default_Buffer_Size); + -- Compress/decompress data fetch from Data_In routine and pass the result + -- to the Data_Out routine. User should provide Data_In and Data_Out + -- for compression/decompression data flow. + -- Compression or decompression depend on Filter initialization. + + function Total_In (Filter : in Filter_Type) return Count; + pragma Inline (Total_In); + -- Returns total number of input bytes read so far + + function Total_Out (Filter : in Filter_Type) return Count; + pragma Inline (Total_Out); + -- Returns total number of bytes output so far + + function CRC32 + (CRC : in Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array) + return Unsigned_32; + pragma Inline (CRC32); + -- Compute CRC32, it could be necessary for make gzip format + + procedure CRC32 + (CRC : in out Unsigned_32; + Data : in Ada.Streams.Stream_Element_Array); + pragma Inline (CRC32); + -- Compute CRC32, it could be necessary for make gzip format + + ------------------------------------------------- + -- Below is more complex low level routines. -- + ------------------------------------------------- + + procedure Translate + (Filter : in out Filter_Type; + In_Data : in Ada.Streams.Stream_Element_Array; + In_Last : out Ada.Streams.Stream_Element_Offset; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + -- Compress/decompress the In_Data buffer and place the result into + -- Out_Data. In_Last is the index of last element from In_Data accepted by + -- the Filter. Out_Last is the last element of the received data from + -- Filter. To tell the filter that incoming data are complete put the + -- Flush parameter to Finish. + + function Stream_End (Filter : in Filter_Type) return Boolean; + pragma Inline (Stream_End); + -- Return the true when the stream is complete. + + procedure Flush + (Filter : in out Filter_Type; + Out_Data : out Ada.Streams.Stream_Element_Array; + Out_Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode); + pragma Inline (Flush); + -- Flushing the data from the compressor. + + generic + with procedure Write + (Item : in Ada.Streams.Stream_Element_Array); + -- User should provide this routine for accept + -- compressed/decompressed data. + + Buffer_Size : in Ada.Streams.Stream_Element_Offset + := Default_Buffer_Size; + -- Buffer size for Write user routine. + + procedure Write + (Filter : in out Filter_Type; + Item : in Ada.Streams.Stream_Element_Array; + Flush : in Flush_Mode := No_Flush); + -- Compress/Decompress data from Item to the generic parameter procedure + -- Write. Output buffer size could be set in Buffer_Size generic parameter. + + generic + with procedure Read + (Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset); + -- User should provide data for compression/decompression + -- thru this routine. + + Buffer : in out Ada.Streams.Stream_Element_Array; + -- Buffer for keep remaining data from the previous + -- back read. + + Rest_First, Rest_Last : in out Ada.Streams.Stream_Element_Offset; + -- Rest_First have to be initialized to Buffer'Last + 1 + -- Rest_Last have to be initialized to Buffer'Last + -- before usage. + + Allow_Read_Some : in Boolean := False; + -- Is it allowed to return Last < Item'Last before end of data. + + procedure Read + (Filter : in out Filter_Type; + Item : out Ada.Streams.Stream_Element_Array; + Last : out Ada.Streams.Stream_Element_Offset; + Flush : in Flush_Mode := No_Flush); + -- Compress/Decompress data from generic parameter procedure Read to the + -- Item. User should provide Buffer and initialized Rest_First, Rest_Last + -- indicators. If Allow_Read_Some is True, Read routines could return + -- Last < Item'Last only at end of stream. + +private + + use Ada.Streams; + + pragma Assert (Ada.Streams.Stream_Element'Size = 8); + pragma Assert (Ada.Streams.Stream_Element'Modulus = 2**8); + + type Flush_Mode is new Integer range 0 .. 5; + + type Compression_Method is new Integer range 8 .. 8; + + type Strategy_Type is new Integer range 0 .. 3; + + No_Flush : constant Flush_Mode := 0; + Partial_Flush : constant Flush_Mode := 1; + Sync_Flush : constant Flush_Mode := 2; + Full_Flush : constant Flush_Mode := 3; + Finish : constant Flush_Mode := 4; + Block_Flush : constant Flush_Mode := 5; + + Filtered : constant Strategy_Type := 1; + Huffman_Only : constant Strategy_Type := 2; + RLE : constant Strategy_Type := 3; + Default_Strategy : constant Strategy_Type := 0; + + Deflated : constant Compression_Method := 8; + + type Z_Stream; + + type Z_Stream_Access is access all Z_Stream; + + type Filter_Type is tagged limited record + Strm : Z_Stream_Access; + Compression : Boolean; + Stream_End : Boolean; + Header : Header_Type; + CRC : Unsigned_32; + Offset : Stream_Element_Offset; + -- Offset for gzip header/footer output. + end record; + +end ZLib; diff --git a/test/zlib/zlib-1.2.8/contrib/ada/zlib.gpr b/test/zlib/zlib-1.2.8/contrib/ada/zlib.gpr new file mode 100644 index 000000000..296b22aa9 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/ada/zlib.gpr @@ -0,0 +1,20 @@ +project Zlib is + + for Languages use ("Ada"); + for Source_Dirs use ("."); + for Object_Dir use "."; + for Main use ("test.adb", "mtest.adb", "read.adb", "buffer_demo"); + + package Compiler is + for Default_Switches ("ada") use ("-gnatwcfilopru", "-gnatVcdfimorst", "-gnatyabcefhiklmnoprst"); + end Compiler; + + package Linker is + for Default_Switches ("ada") use ("-lz"); + end Linker; + + package Builder is + for Default_Switches ("ada") use ("-s", "-gnatQ"); + end Builder; + +end Zlib; diff --git a/test/zlib/zlib-1.2.8/contrib/amd64/amd64-match.S b/test/zlib/zlib-1.2.8/contrib/amd64/amd64-match.S new file mode 100644 index 000000000..81d4a1c94 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/amd64/amd64-match.S @@ -0,0 +1,452 @@ +/* + * match.S -- optimized version of longest_match() + * based on the similar work by Gilles Vollant, and Brian Raiter, written 1998 + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the BSD License. Use by owners of Che Guevarra + * parafernalia is prohibited, where possible, and highly discouraged + * elsewhere. + */ + +#ifndef NO_UNDERLINE +# define match_init _match_init +# define longest_match _longest_match +#endif + +#define scanend ebx +#define scanendw bx +#define chainlenwmask edx /* high word: current chain len low word: s->wmask */ +#define curmatch rsi +#define curmatchd esi +#define windowbestlen r8 +#define scanalign r9 +#define scanalignd r9d +#define window r10 +#define bestlen r11 +#define bestlend r11d +#define scanstart r12d +#define scanstartw r12w +#define scan r13 +#define nicematch r14d +#define limit r15 +#define limitd r15d +#define prev rcx + +/* + * The 258 is a "magic number, not a parameter -- changing it + * breaks the hell loose + */ +#define MAX_MATCH (258) +#define MIN_MATCH (3) +#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1) +#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7) + +/* stack frame offsets */ +#define LocalVarsSize (112) +#define _chainlenwmask ( 8-LocalVarsSize)(%rsp) +#define _windowbestlen (16-LocalVarsSize)(%rsp) +#define save_r14 (24-LocalVarsSize)(%rsp) +#define save_rsi (32-LocalVarsSize)(%rsp) +#define save_rbx (40-LocalVarsSize)(%rsp) +#define save_r12 (56-LocalVarsSize)(%rsp) +#define save_r13 (64-LocalVarsSize)(%rsp) +#define save_r15 (80-LocalVarsSize)(%rsp) + + +.globl match_init, longest_match + +/* + * On AMD64 the first argument of a function (in our case -- the pointer to + * deflate_state structure) is passed in %rdi, hence our offsets below are + * all off of that. + */ + +/* you can check the structure offset by running + +#include +#include +#include "deflate.h" + +void print_depl() +{ +deflate_state ds; +deflate_state *s=&ds; +printf("size pointer=%u\n",(int)sizeof(void*)); + +printf("#define dsWSize (%3u)(%%rdi)\n",(int)(((char*)&(s->w_size))-((char*)s))); +printf("#define dsWMask (%3u)(%%rdi)\n",(int)(((char*)&(s->w_mask))-((char*)s))); +printf("#define dsWindow (%3u)(%%rdi)\n",(int)(((char*)&(s->window))-((char*)s))); +printf("#define dsPrev (%3u)(%%rdi)\n",(int)(((char*)&(s->prev))-((char*)s))); +printf("#define dsMatchLen (%3u)(%%rdi)\n",(int)(((char*)&(s->match_length))-((char*)s))); +printf("#define dsPrevMatch (%3u)(%%rdi)\n",(int)(((char*)&(s->prev_match))-((char*)s))); +printf("#define dsStrStart (%3u)(%%rdi)\n",(int)(((char*)&(s->strstart))-((char*)s))); +printf("#define dsMatchStart (%3u)(%%rdi)\n",(int)(((char*)&(s->match_start))-((char*)s))); +printf("#define dsLookahead (%3u)(%%rdi)\n",(int)(((char*)&(s->lookahead))-((char*)s))); +printf("#define dsPrevLen (%3u)(%%rdi)\n",(int)(((char*)&(s->prev_length))-((char*)s))); +printf("#define dsMaxChainLen (%3u)(%%rdi)\n",(int)(((char*)&(s->max_chain_length))-((char*)s))); +printf("#define dsGoodMatch (%3u)(%%rdi)\n",(int)(((char*)&(s->good_match))-((char*)s))); +printf("#define dsNiceMatch (%3u)(%%rdi)\n",(int)(((char*)&(s->nice_match))-((char*)s))); +} + +*/ + + +/* + to compile for XCode 3.2 on MacOSX x86_64 + - run "gcc -g -c -DXCODE_MAC_X64_STRUCTURE amd64-match.S" + */ + + +#ifndef CURRENT_LINX_XCODE_MAC_X64_STRUCTURE +#define dsWSize ( 68)(%rdi) +#define dsWMask ( 76)(%rdi) +#define dsWindow ( 80)(%rdi) +#define dsPrev ( 96)(%rdi) +#define dsMatchLen (144)(%rdi) +#define dsPrevMatch (148)(%rdi) +#define dsStrStart (156)(%rdi) +#define dsMatchStart (160)(%rdi) +#define dsLookahead (164)(%rdi) +#define dsPrevLen (168)(%rdi) +#define dsMaxChainLen (172)(%rdi) +#define dsGoodMatch (188)(%rdi) +#define dsNiceMatch (192)(%rdi) + +#else + +#ifndef STRUCT_OFFSET +# define STRUCT_OFFSET (0) +#endif + + +#define dsWSize ( 56 + STRUCT_OFFSET)(%rdi) +#define dsWMask ( 64 + STRUCT_OFFSET)(%rdi) +#define dsWindow ( 72 + STRUCT_OFFSET)(%rdi) +#define dsPrev ( 88 + STRUCT_OFFSET)(%rdi) +#define dsMatchLen (136 + STRUCT_OFFSET)(%rdi) +#define dsPrevMatch (140 + STRUCT_OFFSET)(%rdi) +#define dsStrStart (148 + STRUCT_OFFSET)(%rdi) +#define dsMatchStart (152 + STRUCT_OFFSET)(%rdi) +#define dsLookahead (156 + STRUCT_OFFSET)(%rdi) +#define dsPrevLen (160 + STRUCT_OFFSET)(%rdi) +#define dsMaxChainLen (164 + STRUCT_OFFSET)(%rdi) +#define dsGoodMatch (180 + STRUCT_OFFSET)(%rdi) +#define dsNiceMatch (184 + STRUCT_OFFSET)(%rdi) + +#endif + + + + +.text + +/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */ + +longest_match: +/* + * Retrieve the function arguments. %curmatch will hold cur_match + * throughout the entire function (passed via rsi on amd64). + * rdi will hold the pointer to the deflate_state (first arg on amd64) + */ + mov %rsi, save_rsi + mov %rbx, save_rbx + mov %r12, save_r12 + mov %r13, save_r13 + mov %r14, save_r14 + mov %r15, save_r15 + +/* uInt wmask = s->w_mask; */ +/* unsigned chain_length = s->max_chain_length; */ +/* if (s->prev_length >= s->good_match) { */ +/* chain_length >>= 2; */ +/* } */ + + movl dsPrevLen, %eax + movl dsGoodMatch, %ebx + cmpl %ebx, %eax + movl dsWMask, %eax + movl dsMaxChainLen, %chainlenwmask + jl LastMatchGood + shrl $2, %chainlenwmask +LastMatchGood: + +/* chainlen is decremented once beforehand so that the function can */ +/* use the sign flag instead of the zero flag for the exit test. */ +/* It is then shifted into the high word, to make room for the wmask */ +/* value, which it will always accompany. */ + + decl %chainlenwmask + shll $16, %chainlenwmask + orl %eax, %chainlenwmask + +/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */ + + movl dsNiceMatch, %eax + movl dsLookahead, %ebx + cmpl %eax, %ebx + jl LookaheadLess + movl %eax, %ebx +LookaheadLess: movl %ebx, %nicematch + +/* register Bytef *scan = s->window + s->strstart; */ + + mov dsWindow, %window + movl dsStrStart, %limitd + lea (%limit, %window), %scan + +/* Determine how many bytes the scan ptr is off from being */ +/* dword-aligned. */ + + mov %scan, %scanalign + negl %scanalignd + andl $3, %scanalignd + +/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ +/* s->strstart - (IPos)MAX_DIST(s) : NIL; */ + + movl dsWSize, %eax + subl $MIN_LOOKAHEAD, %eax + xorl %ecx, %ecx + subl %eax, %limitd + cmovng %ecx, %limitd + +/* int best_len = s->prev_length; */ + + movl dsPrevLen, %bestlend + +/* Store the sum of s->window + best_len in %windowbestlen locally, and in memory. */ + + lea (%window, %bestlen), %windowbestlen + mov %windowbestlen, _windowbestlen + +/* register ush scan_start = *(ushf*)scan; */ +/* register ush scan_end = *(ushf*)(scan+best_len-1); */ +/* Posf *prev = s->prev; */ + + movzwl (%scan), %scanstart + movzwl -1(%scan, %bestlen), %scanend + mov dsPrev, %prev + +/* Jump into the main loop. */ + + movl %chainlenwmask, _chainlenwmask + jmp LoopEntry + +.balign 16 + +/* do { + * match = s->window + cur_match; + * if (*(ushf*)(match+best_len-1) != scan_end || + * *(ushf*)match != scan_start) continue; + * [...] + * } while ((cur_match = prev[cur_match & wmask]) > limit + * && --chain_length != 0); + * + * Here is the inner loop of the function. The function will spend the + * majority of its time in this loop, and majority of that time will + * be spent in the first ten instructions. + */ +LookupLoop: + andl %chainlenwmask, %curmatchd + movzwl (%prev, %curmatch, 2), %curmatchd + cmpl %limitd, %curmatchd + jbe LeaveNow + subl $0x00010000, %chainlenwmask + js LeaveNow +LoopEntry: cmpw -1(%windowbestlen, %curmatch), %scanendw + jne LookupLoop + cmpw %scanstartw, (%window, %curmatch) + jne LookupLoop + +/* Store the current value of chainlen. */ + movl %chainlenwmask, _chainlenwmask + +/* %scan is the string under scrutiny, and %prev to the string we */ +/* are hoping to match it up with. In actuality, %esi and %edi are */ +/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */ +/* initialized to -(MAX_MATCH_8 - scanalign). */ + + mov $(-MAX_MATCH_8), %rdx + lea (%curmatch, %window), %windowbestlen + lea MAX_MATCH_8(%windowbestlen, %scanalign), %windowbestlen + lea MAX_MATCH_8(%scan, %scanalign), %prev + +/* the prefetching below makes very little difference... */ + prefetcht1 (%windowbestlen, %rdx) + prefetcht1 (%prev, %rdx) + +/* + * Test the strings for equality, 8 bytes at a time. At the end, + * adjust %rdx so that it is offset to the exact byte that mismatched. + * + * It should be confessed that this loop usually does not represent + * much of the total running time. Replacing it with a more + * straightforward "rep cmpsb" would not drastically degrade + * performance -- unrolling it, for example, makes no difference. + */ + +#undef USE_SSE /* works, but is 6-7% slower, than non-SSE... */ + +LoopCmps: +#ifdef USE_SSE + /* Preload the SSE registers */ + movdqu (%windowbestlen, %rdx), %xmm1 + movdqu (%prev, %rdx), %xmm2 + pcmpeqb %xmm2, %xmm1 + movdqu 16(%windowbestlen, %rdx), %xmm3 + movdqu 16(%prev, %rdx), %xmm4 + pcmpeqb %xmm4, %xmm3 + movdqu 32(%windowbestlen, %rdx), %xmm5 + movdqu 32(%prev, %rdx), %xmm6 + pcmpeqb %xmm6, %xmm5 + movdqu 48(%windowbestlen, %rdx), %xmm7 + movdqu 48(%prev, %rdx), %xmm8 + pcmpeqb %xmm8, %xmm7 + + /* Check the comparisions' results */ + pmovmskb %xmm1, %rax + notw %ax + bsfw %ax, %ax + jnz LeaveLoopCmps + + /* this is the only iteration of the loop with a possibility of having + incremented rdx by 0x108 (each loop iteration add 16*4 = 0x40 + and (0x40*4)+8=0x108 */ + add $8, %rdx + jz LenMaximum + add $8, %rdx + + + pmovmskb %xmm3, %rax + notw %ax + bsfw %ax, %ax + jnz LeaveLoopCmps + + + add $16, %rdx + + + pmovmskb %xmm5, %rax + notw %ax + bsfw %ax, %ax + jnz LeaveLoopCmps + + add $16, %rdx + + + pmovmskb %xmm7, %rax + notw %ax + bsfw %ax, %ax + jnz LeaveLoopCmps + + add $16, %rdx + + jmp LoopCmps +LeaveLoopCmps: add %rax, %rdx +#else + mov (%windowbestlen, %rdx), %rax + xor (%prev, %rdx), %rax + jnz LeaveLoopCmps + + mov 8(%windowbestlen, %rdx), %rax + xor 8(%prev, %rdx), %rax + jnz LeaveLoopCmps8 + + mov 16(%windowbestlen, %rdx), %rax + xor 16(%prev, %rdx), %rax + jnz LeaveLoopCmps16 + + add $24, %rdx + jnz LoopCmps + jmp LenMaximum +# if 0 +/* + * This three-liner is tantalizingly simple, but bsf is a slow instruction, + * and the complicated alternative down below is quite a bit faster. Sad... + */ + +LeaveLoopCmps: bsf %rax, %rax /* find the first non-zero bit */ + shrl $3, %eax /* divide by 8 to get the byte */ + add %rax, %rdx +# else +LeaveLoopCmps16: + add $8, %rdx +LeaveLoopCmps8: + add $8, %rdx +LeaveLoopCmps: testl $0xFFFFFFFF, %eax /* Check the first 4 bytes */ + jnz Check16 + add $4, %rdx + shr $32, %rax +Check16: testw $0xFFFF, %ax + jnz LenLower + add $2, %rdx + shrl $16, %eax +LenLower: subb $1, %al + adc $0, %rdx +# endif +#endif + +/* Calculate the length of the match. If it is longer than MAX_MATCH, */ +/* then automatically accept it as the best possible match and leave. */ + + lea (%prev, %rdx), %rax + sub %scan, %rax + cmpl $MAX_MATCH, %eax + jge LenMaximum + +/* If the length of the match is not longer than the best match we */ +/* have so far, then forget it and return to the lookup loop. */ + + cmpl %bestlend, %eax + jg LongerMatch + mov _windowbestlen, %windowbestlen + mov dsPrev, %prev + movl _chainlenwmask, %edx + jmp LookupLoop + +/* s->match_start = cur_match; */ +/* best_len = len; */ +/* if (len >= nice_match) break; */ +/* scan_end = *(ushf*)(scan+best_len-1); */ + +LongerMatch: + movl %eax, %bestlend + movl %curmatchd, dsMatchStart + cmpl %nicematch, %eax + jge LeaveNow + + lea (%window, %bestlen), %windowbestlen + mov %windowbestlen, _windowbestlen + + movzwl -1(%scan, %rax), %scanend + mov dsPrev, %prev + movl _chainlenwmask, %chainlenwmask + jmp LookupLoop + +/* Accept the current string, with the maximum possible length. */ + +LenMaximum: + movl $MAX_MATCH, %bestlend + movl %curmatchd, dsMatchStart + +/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ +/* return s->lookahead; */ + +LeaveNow: + movl dsLookahead, %eax + cmpl %eax, %bestlend + cmovngl %bestlend, %eax +LookaheadRet: + +/* Restore the registers and return from whence we came. */ + + mov save_rsi, %rsi + mov save_rbx, %rbx + mov save_r12, %r12 + mov save_r13, %r13 + mov save_r14, %r14 + mov save_r15, %r15 + + ret + +match_init: ret diff --git a/test/zlib/zlib-1.2.8/contrib/asm686/README.686 b/test/zlib/zlib-1.2.8/contrib/asm686/README.686 new file mode 100644 index 000000000..a0bf3bea4 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/asm686/README.686 @@ -0,0 +1,51 @@ +This is a patched version of zlib, modified to use +Pentium-Pro-optimized assembly code in the deflation algorithm. The +files changed/added by this patch are: + +README.686 +match.S + +The speedup that this patch provides varies, depending on whether the +compiler used to build the original version of zlib falls afoul of the +PPro's speed traps. My own tests show a speedup of around 10-20% at +the default compression level, and 20-30% using -9, against a version +compiled using gcc 2.7.2.3. Your mileage may vary. + +Note that this code has been tailored for the PPro/PII in particular, +and will not perform particuarly well on a Pentium. + +If you are using an assembler other than GNU as, you will have to +translate match.S to use your assembler's syntax. (Have fun.) + +Brian Raiter +breadbox@muppetlabs.com +April, 1998 + + +Added for zlib 1.1.3: + +The patches come from +http://www.muppetlabs.com/~breadbox/software/assembly.html + +To compile zlib with this asm file, copy match.S to the zlib directory +then do: + +CFLAGS="-O3 -DASMV" ./configure +make OBJA=match.o + + +Update: + +I've been ignoring these assembly routines for years, believing that +gcc's generated code had caught up with it sometime around gcc 2.95 +and the major rearchitecting of the Pentium 4. However, I recently +learned that, despite what I believed, this code still has some life +in it. On the Pentium 4 and AMD64 chips, it continues to run about 8% +faster than the code produced by gcc 4.1. + +In acknowledgement of its continuing usefulness, I've altered the +license to match that of the rest of zlib. Share and Enjoy! + +Brian Raiter +breadbox@muppetlabs.com +April, 2007 diff --git a/test/zlib/zlib-1.2.8/contrib/asm686/match.S b/test/zlib/zlib-1.2.8/contrib/asm686/match.S new file mode 100644 index 000000000..fa4210927 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/asm686/match.S @@ -0,0 +1,357 @@ +/* match.S -- x86 assembly version of the zlib longest_match() function. + * Optimized for the Intel 686 chips (PPro and later). + * + * Copyright (C) 1998, 2007 Brian Raiter + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the author be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef NO_UNDERLINE +#define match_init _match_init +#define longest_match _longest_match +#endif + +#define MAX_MATCH (258) +#define MIN_MATCH (3) +#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1) +#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7) + +/* stack frame offsets */ + +#define chainlenwmask 0 /* high word: current chain len */ + /* low word: s->wmask */ +#define window 4 /* local copy of s->window */ +#define windowbestlen 8 /* s->window + bestlen */ +#define scanstart 16 /* first two bytes of string */ +#define scanend 12 /* last two bytes of string */ +#define scanalign 20 /* dword-misalignment of string */ +#define nicematch 24 /* a good enough match size */ +#define bestlen 28 /* size of best match so far */ +#define scan 32 /* ptr to string wanting match */ + +#define LocalVarsSize (36) +/* saved ebx 36 */ +/* saved edi 40 */ +/* saved esi 44 */ +/* saved ebp 48 */ +/* return address 52 */ +#define deflatestate 56 /* the function arguments */ +#define curmatch 60 + +/* All the +zlib1222add offsets are due to the addition of fields + * in zlib in the deflate_state structure since the asm code was first written + * (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). + * (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). + * if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). + */ + +#define zlib1222add (8) + +#define dsWSize (36+zlib1222add) +#define dsWMask (44+zlib1222add) +#define dsWindow (48+zlib1222add) +#define dsPrev (56+zlib1222add) +#define dsMatchLen (88+zlib1222add) +#define dsPrevMatch (92+zlib1222add) +#define dsStrStart (100+zlib1222add) +#define dsMatchStart (104+zlib1222add) +#define dsLookahead (108+zlib1222add) +#define dsPrevLen (112+zlib1222add) +#define dsMaxChainLen (116+zlib1222add) +#define dsGoodMatch (132+zlib1222add) +#define dsNiceMatch (136+zlib1222add) + + +.file "match.S" + +.globl match_init, longest_match + +.text + +/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */ +.cfi_sections .debug_frame + +longest_match: + +.cfi_startproc +/* Save registers that the compiler may be using, and adjust %esp to */ +/* make room for our stack frame. */ + + pushl %ebp + .cfi_def_cfa_offset 8 + .cfi_offset ebp, -8 + pushl %edi + .cfi_def_cfa_offset 12 + pushl %esi + .cfi_def_cfa_offset 16 + pushl %ebx + .cfi_def_cfa_offset 20 + subl $LocalVarsSize, %esp + .cfi_def_cfa_offset LocalVarsSize+20 + +/* Retrieve the function arguments. %ecx will hold cur_match */ +/* throughout the entire function. %edx will hold the pointer to the */ +/* deflate_state structure during the function's setup (before */ +/* entering the main loop). */ + + movl deflatestate(%esp), %edx + movl curmatch(%esp), %ecx + +/* uInt wmask = s->w_mask; */ +/* unsigned chain_length = s->max_chain_length; */ +/* if (s->prev_length >= s->good_match) { */ +/* chain_length >>= 2; */ +/* } */ + + movl dsPrevLen(%edx), %eax + movl dsGoodMatch(%edx), %ebx + cmpl %ebx, %eax + movl dsWMask(%edx), %eax + movl dsMaxChainLen(%edx), %ebx + jl LastMatchGood + shrl $2, %ebx +LastMatchGood: + +/* chainlen is decremented once beforehand so that the function can */ +/* use the sign flag instead of the zero flag for the exit test. */ +/* It is then shifted into the high word, to make room for the wmask */ +/* value, which it will always accompany. */ + + decl %ebx + shll $16, %ebx + orl %eax, %ebx + movl %ebx, chainlenwmask(%esp) + +/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */ + + movl dsNiceMatch(%edx), %eax + movl dsLookahead(%edx), %ebx + cmpl %eax, %ebx + jl LookaheadLess + movl %eax, %ebx +LookaheadLess: movl %ebx, nicematch(%esp) + +/* register Bytef *scan = s->window + s->strstart; */ + + movl dsWindow(%edx), %esi + movl %esi, window(%esp) + movl dsStrStart(%edx), %ebp + lea (%esi,%ebp), %edi + movl %edi, scan(%esp) + +/* Determine how many bytes the scan ptr is off from being */ +/* dword-aligned. */ + + movl %edi, %eax + negl %eax + andl $3, %eax + movl %eax, scanalign(%esp) + +/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */ +/* s->strstart - (IPos)MAX_DIST(s) : NIL; */ + + movl dsWSize(%edx), %eax + subl $MIN_LOOKAHEAD, %eax + subl %eax, %ebp + jg LimitPositive + xorl %ebp, %ebp +LimitPositive: + +/* int best_len = s->prev_length; */ + + movl dsPrevLen(%edx), %eax + movl %eax, bestlen(%esp) + +/* Store the sum of s->window + best_len in %esi locally, and in %esi. */ + + addl %eax, %esi + movl %esi, windowbestlen(%esp) + +/* register ush scan_start = *(ushf*)scan; */ +/* register ush scan_end = *(ushf*)(scan+best_len-1); */ +/* Posf *prev = s->prev; */ + + movzwl (%edi), %ebx + movl %ebx, scanstart(%esp) + movzwl -1(%edi,%eax), %ebx + movl %ebx, scanend(%esp) + movl dsPrev(%edx), %edi + +/* Jump into the main loop. */ + + movl chainlenwmask(%esp), %edx + jmp LoopEntry + +.balign 16 + +/* do { + * match = s->window + cur_match; + * if (*(ushf*)(match+best_len-1) != scan_end || + * *(ushf*)match != scan_start) continue; + * [...] + * } while ((cur_match = prev[cur_match & wmask]) > limit + * && --chain_length != 0); + * + * Here is the inner loop of the function. The function will spend the + * majority of its time in this loop, and majority of that time will + * be spent in the first ten instructions. + * + * Within this loop: + * %ebx = scanend + * %ecx = curmatch + * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) + * %esi = windowbestlen - i.e., (window + bestlen) + * %edi = prev + * %ebp = limit + */ +LookupLoop: + andl %edx, %ecx + movzwl (%edi,%ecx,2), %ecx + cmpl %ebp, %ecx + jbe LeaveNow + subl $0x00010000, %edx + js LeaveNow +LoopEntry: movzwl -1(%esi,%ecx), %eax + cmpl %ebx, %eax + jnz LookupLoop + movl window(%esp), %eax + movzwl (%eax,%ecx), %eax + cmpl scanstart(%esp), %eax + jnz LookupLoop + +/* Store the current value of chainlen. */ + + movl %edx, chainlenwmask(%esp) + +/* Point %edi to the string under scrutiny, and %esi to the string we */ +/* are hoping to match it up with. In actuality, %esi and %edi are */ +/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */ +/* initialized to -(MAX_MATCH_8 - scanalign). */ + + movl window(%esp), %esi + movl scan(%esp), %edi + addl %ecx, %esi + movl scanalign(%esp), %eax + movl $(-MAX_MATCH_8), %edx + lea MAX_MATCH_8(%edi,%eax), %edi + lea MAX_MATCH_8(%esi,%eax), %esi + +/* Test the strings for equality, 8 bytes at a time. At the end, + * adjust %edx so that it is offset to the exact byte that mismatched. + * + * We already know at this point that the first three bytes of the + * strings match each other, and they can be safely passed over before + * starting the compare loop. So what this code does is skip over 0-3 + * bytes, as much as necessary in order to dword-align the %edi + * pointer. (%esi will still be misaligned three times out of four.) + * + * It should be confessed that this loop usually does not represent + * much of the total running time. Replacing it with a more + * straightforward "rep cmpsb" would not drastically degrade + * performance. + */ +LoopCmps: + movl (%esi,%edx), %eax + xorl (%edi,%edx), %eax + jnz LeaveLoopCmps + movl 4(%esi,%edx), %eax + xorl 4(%edi,%edx), %eax + jnz LeaveLoopCmps4 + addl $8, %edx + jnz LoopCmps + jmp LenMaximum +LeaveLoopCmps4: addl $4, %edx +LeaveLoopCmps: testl $0x0000FFFF, %eax + jnz LenLower + addl $2, %edx + shrl $16, %eax +LenLower: subb $1, %al + adcl $0, %edx + +/* Calculate the length of the match. If it is longer than MAX_MATCH, */ +/* then automatically accept it as the best possible match and leave. */ + + lea (%edi,%edx), %eax + movl scan(%esp), %edi + subl %edi, %eax + cmpl $MAX_MATCH, %eax + jge LenMaximum + +/* If the length of the match is not longer than the best match we */ +/* have so far, then forget it and return to the lookup loop. */ + + movl deflatestate(%esp), %edx + movl bestlen(%esp), %ebx + cmpl %ebx, %eax + jg LongerMatch + movl windowbestlen(%esp), %esi + movl dsPrev(%edx), %edi + movl scanend(%esp), %ebx + movl chainlenwmask(%esp), %edx + jmp LookupLoop + +/* s->match_start = cur_match; */ +/* best_len = len; */ +/* if (len >= nice_match) break; */ +/* scan_end = *(ushf*)(scan+best_len-1); */ + +LongerMatch: movl nicematch(%esp), %ebx + movl %eax, bestlen(%esp) + movl %ecx, dsMatchStart(%edx) + cmpl %ebx, %eax + jge LeaveNow + movl window(%esp), %esi + addl %eax, %esi + movl %esi, windowbestlen(%esp) + movzwl -1(%edi,%eax), %ebx + movl dsPrev(%edx), %edi + movl %ebx, scanend(%esp) + movl chainlenwmask(%esp), %edx + jmp LookupLoop + +/* Accept the current string, with the maximum possible length. */ + +LenMaximum: movl deflatestate(%esp), %edx + movl $MAX_MATCH, bestlen(%esp) + movl %ecx, dsMatchStart(%edx) + +/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */ +/* return s->lookahead; */ + +LeaveNow: + movl deflatestate(%esp), %edx + movl bestlen(%esp), %ebx + movl dsLookahead(%edx), %eax + cmpl %eax, %ebx + jg LookaheadRet + movl %ebx, %eax +LookaheadRet: + +/* Restore the stack and return from whence we came. */ + + addl $LocalVarsSize, %esp + .cfi_def_cfa_offset 20 + popl %ebx + .cfi_def_cfa_offset 16 + popl %esi + .cfi_def_cfa_offset 12 + popl %edi + .cfi_def_cfa_offset 8 + popl %ebp + .cfi_def_cfa_offset 4 +.cfi_endproc +match_init: ret diff --git a/test/zlib/zlib-1.2.8/contrib/blast/Makefile b/test/zlib/zlib-1.2.8/contrib/blast/Makefile new file mode 100644 index 000000000..9be80bafe --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/blast/Makefile @@ -0,0 +1,8 @@ +blast: blast.c blast.h + cc -DTEST -o blast blast.c + +test: blast + blast < test.pk | cmp - test.txt + +clean: + rm -f blast blast.o diff --git a/test/zlib/zlib-1.2.8/contrib/blast/README b/test/zlib/zlib-1.2.8/contrib/blast/README new file mode 100644 index 000000000..e3a60b3f5 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/blast/README @@ -0,0 +1,4 @@ +Read blast.h for purpose and usage. + +Mark Adler +madler@alumni.caltech.edu diff --git a/test/zlib/zlib-1.2.8/contrib/blast/blast.c b/test/zlib/zlib-1.2.8/contrib/blast/blast.c new file mode 100644 index 000000000..69ef0fe00 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/blast/blast.c @@ -0,0 +1,446 @@ +/* blast.c + * Copyright (C) 2003, 2012 Mark Adler + * For conditions of distribution and use, see copyright notice in blast.h + * version 1.2, 24 Oct 2012 + * + * blast.c decompresses data compressed by the PKWare Compression Library. + * This function provides functionality similar to the explode() function of + * the PKWare library, hence the name "blast". + * + * This decompressor is based on the excellent format description provided by + * Ben Rudiak-Gould in comp.compression on August 13, 2001. Interestingly, the + * example Ben provided in the post is incorrect. The distance 110001 should + * instead be 111000. When corrected, the example byte stream becomes: + * + * 00 04 82 24 25 8f 80 7f + * + * which decompresses to "AIAIAIAIAIAIA" (without the quotes). + */ + +/* + * Change history: + * + * 1.0 12 Feb 2003 - First version + * 1.1 16 Feb 2003 - Fixed distance check for > 4 GB uncompressed data + * 1.2 24 Oct 2012 - Add note about using binary mode in stdio + * - Fix comparisons of differently signed integers + */ + +#include /* for setjmp(), longjmp(), and jmp_buf */ +#include "blast.h" /* prototype for blast() */ + +#define local static /* for local function definitions */ +#define MAXBITS 13 /* maximum code length */ +#define MAXWIN 4096 /* maximum window size */ + +/* input and output state */ +struct state { + /* input state */ + blast_in infun; /* input function provided by user */ + void *inhow; /* opaque information passed to infun() */ + unsigned char *in; /* next input location */ + unsigned left; /* available input at in */ + int bitbuf; /* bit buffer */ + int bitcnt; /* number of bits in bit buffer */ + + /* input limit error return state for bits() and decode() */ + jmp_buf env; + + /* output state */ + blast_out outfun; /* output function provided by user */ + void *outhow; /* opaque information passed to outfun() */ + unsigned next; /* index of next write location in out[] */ + int first; /* true to check distances (for first 4K) */ + unsigned char out[MAXWIN]; /* output buffer and sliding window */ +}; + +/* + * Return need bits from the input stream. This always leaves less than + * eight bits in the buffer. bits() works properly for need == 0. + * + * Format notes: + * + * - Bits are stored in bytes from the least significant bit to the most + * significant bit. Therefore bits are dropped from the bottom of the bit + * buffer, using shift right, and new bytes are appended to the top of the + * bit buffer, using shift left. + */ +local int bits(struct state *s, int need) +{ + int val; /* bit accumulator */ + + /* load at least need bits into val */ + val = s->bitbuf; + while (s->bitcnt < need) { + if (s->left == 0) { + s->left = s->infun(s->inhow, &(s->in)); + if (s->left == 0) longjmp(s->env, 1); /* out of input */ + } + val |= (int)(*(s->in)++) << s->bitcnt; /* load eight bits */ + s->left--; + s->bitcnt += 8; + } + + /* drop need bits and update buffer, always zero to seven bits left */ + s->bitbuf = val >> need; + s->bitcnt -= need; + + /* return need bits, zeroing the bits above that */ + return val & ((1 << need) - 1); +} + +/* + * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of + * each length, which for a canonical code are stepped through in order. + * symbol[] are the symbol values in canonical order, where the number of + * entries is the sum of the counts in count[]. The decoding process can be + * seen in the function decode() below. + */ +struct huffman { + short *count; /* number of symbols of each length */ + short *symbol; /* canonically ordered symbols */ +}; + +/* + * Decode a code from the stream s using huffman table h. Return the symbol or + * a negative value if there is an error. If all of the lengths are zero, i.e. + * an empty code, or if the code is incomplete and an invalid code is received, + * then -9 is returned after reading MAXBITS bits. + * + * Format notes: + * + * - The codes as stored in the compressed data are bit-reversed relative to + * a simple integer ordering of codes of the same lengths. Hence below the + * bits are pulled from the compressed data one at a time and used to + * build the code value reversed from what is in the stream in order to + * permit simple integer comparisons for decoding. + * + * - The first code for the shortest length is all ones. Subsequent codes of + * the same length are simply integer decrements of the previous code. When + * moving up a length, a one bit is appended to the code. For a complete + * code, the last code of the longest length will be all zeros. To support + * this ordering, the bits pulled during decoding are inverted to apply the + * more "natural" ordering starting with all zeros and incrementing. + */ +local int decode(struct state *s, struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + int bitbuf; /* bits from stream */ + int left; /* bits left in next or left to process */ + short *next; /* next number of codes */ + + bitbuf = s->bitbuf; + left = s->bitcnt; + code = first = index = 0; + len = 1; + next = h->count + 1; + while (1) { + while (left--) { + code |= (bitbuf & 1) ^ 1; /* invert code */ + bitbuf >>= 1; + count = *next++; + if (code < first + count) { /* if length len, return symbol */ + s->bitbuf = bitbuf; + s->bitcnt = (s->bitcnt - len) & 7; + return h->symbol[index + (code - first)]; + } + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + len++; + } + left = (MAXBITS+1) - len; + if (left == 0) break; + if (s->left == 0) { + s->left = s->infun(s->inhow, &(s->in)); + if (s->left == 0) longjmp(s->env, 1); /* out of input */ + } + bitbuf = *(s->in)++; + s->left--; + if (left > 8) left = 8; + } + return -9; /* ran out of codes */ +} + +/* + * Given a list of repeated code lengths rep[0..n-1], where each byte is a + * count (high four bits + 1) and a code length (low four bits), generate the + * list of code lengths. This compaction reduces the size of the object code. + * Then given the list of code lengths length[0..n-1] representing a canonical + * Huffman code for n symbols, construct the tables required to decode those + * codes. Those tables are the number of codes of each length, and the symbols + * sorted by length, retaining their original order within each length. The + * return value is zero for a complete code set, negative for an over- + * subscribed code set, and positive for an incomplete code set. The tables + * can be used if the return value is zero or positive, but they cannot be used + * if the return value is negative. If the return value is zero, it is not + * possible for decode() using that table to return an error--any stream of + * enough bits will resolve to a symbol. If the return value is positive, then + * it is possible for decode() using that table to return an error for received + * codes past the end of the incomplete lengths. + */ +local int construct(struct huffman *h, const unsigned char *rep, int n) +{ + int symbol; /* current symbol when stepping through length[] */ + int len; /* current length when stepping through h->count[] */ + int left; /* number of possible codes left of current length */ + short offs[MAXBITS+1]; /* offsets in symbol table for each length */ + short length[256]; /* code lengths */ + + /* convert compact repeat counts into symbol bit length list */ + symbol = 0; + do { + len = *rep++; + left = (len >> 4) + 1; + len &= 15; + do { + length[symbol++] = len; + } while (--left); + } while (--n); + n = symbol; + + /* count number of codes of each length */ + for (len = 0; len <= MAXBITS; len++) + h->count[len] = 0; + for (symbol = 0; symbol < n; symbol++) + (h->count[length[symbol]])++; /* assumes lengths are within bounds */ + if (h->count[0] == n) /* no codes! */ + return 0; /* complete, but decode() will fail */ + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; /* one possible code of zero length */ + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; /* one more bit, double codes left */ + left -= h->count[len]; /* deduct count from possible codes */ + if (left < 0) return left; /* over-subscribed--return negative */ + } /* left > 0 means incomplete */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + h->count[len]; + + /* + * put symbols in table sorted by length, by symbol order within each + * length + */ + for (symbol = 0; symbol < n; symbol++) + if (length[symbol] != 0) + h->symbol[offs[length[symbol]]++] = symbol; + + /* return zero for complete set, positive for incomplete set */ + return left; +} + +/* + * Decode PKWare Compression Library stream. + * + * Format notes: + * + * - First byte is 0 if literals are uncoded or 1 if they are coded. Second + * byte is 4, 5, or 6 for the number of extra bits in the distance code. + * This is the base-2 logarithm of the dictionary size minus six. + * + * - Compressed data is a combination of literals and length/distance pairs + * terminated by an end code. Literals are either Huffman coded or + * uncoded bytes. A length/distance pair is a coded length followed by a + * coded distance to represent a string that occurs earlier in the + * uncompressed data that occurs again at the current location. + * + * - A bit preceding a literal or length/distance pair indicates which comes + * next, 0 for literals, 1 for length/distance. + * + * - If literals are uncoded, then the next eight bits are the literal, in the + * normal bit order in th stream, i.e. no bit-reversal is needed. Similarly, + * no bit reversal is needed for either the length extra bits or the distance + * extra bits. + * + * - Literal bytes are simply written to the output. A length/distance pair is + * an instruction to copy previously uncompressed bytes to the output. The + * copy is from distance bytes back in the output stream, copying for length + * bytes. + * + * - Distances pointing before the beginning of the output data are not + * permitted. + * + * - Overlapped copies, where the length is greater than the distance, are + * allowed and common. For example, a distance of one and a length of 518 + * simply copies the last byte 518 times. A distance of four and a length of + * twelve copies the last four bytes three times. A simple forward copy + * ignoring whether the length is greater than the distance or not implements + * this correctly. + */ +local int decomp(struct state *s) +{ + int lit; /* true if literals are coded */ + int dict; /* log2(dictionary size) - 6 */ + int symbol; /* decoded symbol, extra bits for distance */ + int len; /* length for copy */ + unsigned dist; /* distance for copy */ + int copy; /* copy counter */ + unsigned char *from, *to; /* copy pointers */ + static int virgin = 1; /* build tables once */ + static short litcnt[MAXBITS+1], litsym[256]; /* litcode memory */ + static short lencnt[MAXBITS+1], lensym[16]; /* lencode memory */ + static short distcnt[MAXBITS+1], distsym[64]; /* distcode memory */ + static struct huffman litcode = {litcnt, litsym}; /* length code */ + static struct huffman lencode = {lencnt, lensym}; /* length code */ + static struct huffman distcode = {distcnt, distsym};/* distance code */ + /* bit lengths of literal codes */ + static const unsigned char litlen[] = { + 11, 124, 8, 7, 28, 7, 188, 13, 76, 4, 10, 8, 12, 10, 12, 10, 8, 23, 8, + 9, 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, 12, 11, 7, 9, 11, 12, 6, 7, 22, 5, + 7, 24, 6, 11, 9, 6, 7, 22, 7, 11, 38, 7, 9, 8, 25, 11, 8, 11, 9, 12, + 8, 12, 5, 38, 5, 38, 5, 11, 7, 5, 6, 21, 6, 10, 53, 8, 7, 24, 10, 27, + 44, 253, 253, 253, 252, 252, 252, 13, 12, 45, 12, 45, 12, 61, 12, 45, + 44, 173}; + /* bit lengths of length codes 0..15 */ + static const unsigned char lenlen[] = {2, 35, 36, 53, 38, 23}; + /* bit lengths of distance codes 0..63 */ + static const unsigned char distlen[] = {2, 20, 53, 230, 247, 151, 248}; + static const short base[16] = { /* base for length codes */ + 3, 2, 4, 5, 6, 7, 8, 9, 10, 12, 16, 24, 40, 72, 136, 264}; + static const char extra[16] = { /* extra bits for length codes */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8}; + + /* set up decoding tables (once--might not be thread-safe) */ + if (virgin) { + construct(&litcode, litlen, sizeof(litlen)); + construct(&lencode, lenlen, sizeof(lenlen)); + construct(&distcode, distlen, sizeof(distlen)); + virgin = 0; + } + + /* read header */ + lit = bits(s, 8); + if (lit > 1) return -1; + dict = bits(s, 8); + if (dict < 4 || dict > 6) return -2; + + /* decode literals and length/distance pairs */ + do { + if (bits(s, 1)) { + /* get length */ + symbol = decode(s, &lencode); + len = base[symbol] + bits(s, extra[symbol]); + if (len == 519) break; /* end code */ + + /* get distance */ + symbol = len == 2 ? 2 : dict; + dist = decode(s, &distcode) << symbol; + dist += bits(s, symbol); + dist++; + if (s->first && dist > s->next) + return -3; /* distance too far back */ + + /* copy length bytes from distance bytes back */ + do { + to = s->out + s->next; + from = to - dist; + copy = MAXWIN; + if (s->next < dist) { + from += copy; + copy = dist; + } + copy -= s->next; + if (copy > len) copy = len; + len -= copy; + s->next += copy; + do { + *to++ = *from++; + } while (--copy); + if (s->next == MAXWIN) { + if (s->outfun(s->outhow, s->out, s->next)) return 1; + s->next = 0; + s->first = 0; + } + } while (len != 0); + } + else { + /* get literal and write it */ + symbol = lit ? decode(s, &litcode) : bits(s, 8); + s->out[s->next++] = symbol; + if (s->next == MAXWIN) { + if (s->outfun(s->outhow, s->out, s->next)) return 1; + s->next = 0; + s->first = 0; + } + } + } while (1); + return 0; +} + +/* See comments in blast.h */ +int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow) +{ + struct state s; /* input/output state */ + int err; /* return value */ + + /* initialize input state */ + s.infun = infun; + s.inhow = inhow; + s.left = 0; + s.bitbuf = 0; + s.bitcnt = 0; + + /* initialize output state */ + s.outfun = outfun; + s.outhow = outhow; + s.next = 0; + s.first = 1; + + /* return if bits() or decode() tries to read past available input */ + if (setjmp(s.env) != 0) /* if came back here via longjmp(), */ + err = 2; /* then skip decomp(), return error */ + else + err = decomp(&s); /* decompress */ + + /* write any leftover output and update the error code if needed */ + if (err != 1 && s.next && s.outfun(s.outhow, s.out, s.next) && err == 0) + err = 1; + return err; +} + +#ifdef TEST +/* Example of how to use blast() */ +#include +#include + +#define CHUNK 16384 + +local unsigned inf(void *how, unsigned char **buf) +{ + static unsigned char hold[CHUNK]; + + *buf = hold; + return fread(hold, 1, CHUNK, (FILE *)how); +} + +local int outf(void *how, unsigned char *buf, unsigned len) +{ + return fwrite(buf, 1, len, (FILE *)how) != len; +} + +/* Decompress a PKWare Compression Library stream from stdin to stdout */ +int main(void) +{ + int ret, n; + + /* decompress to stdout */ + ret = blast(inf, stdin, outf, stdout); + if (ret != 0) fprintf(stderr, "blast error: %d\n", ret); + + /* see if there are any leftover bytes */ + n = 0; + while (getchar() != EOF) n++; + if (n) fprintf(stderr, "blast warning: %d unused bytes of input\n", n); + + /* return blast() error code */ + return ret; +} +#endif diff --git a/test/zlib/zlib-1.2.8/contrib/blast/blast.h b/test/zlib/zlib-1.2.8/contrib/blast/blast.h new file mode 100644 index 000000000..658cfd320 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/blast/blast.h @@ -0,0 +1,75 @@ +/* blast.h -- interface for blast.c + Copyright (C) 2003, 2012 Mark Adler + version 1.2, 24 Oct 2012 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + + +/* + * blast() decompresses the PKWare Data Compression Library (DCL) compressed + * format. It provides the same functionality as the explode() function in + * that library. (Note: PKWare overused the "implode" verb, and the format + * used by their library implode() function is completely different and + * incompatible with the implode compression method supported by PKZIP.) + * + * The binary mode for stdio functions should be used to assure that the + * compressed data is not corrupted when read or written. For example: + * fopen(..., "rb") and fopen(..., "wb"). + */ + + +typedef unsigned (*blast_in)(void *how, unsigned char **buf); +typedef int (*blast_out)(void *how, unsigned char *buf, unsigned len); +/* Definitions for input/output functions passed to blast(). See below for + * what the provided functions need to do. + */ + + +int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow); +/* Decompress input to output using the provided infun() and outfun() calls. + * On success, the return value of blast() is zero. If there is an error in + * the source data, i.e. it is not in the proper format, then a negative value + * is returned. If there is not enough input available or there is not enough + * output space, then a positive error is returned. + * + * The input function is invoked: len = infun(how, &buf), where buf is set by + * infun() to point to the input buffer, and infun() returns the number of + * available bytes there. If infun() returns zero, then blast() returns with + * an input error. (blast() only asks for input if it needs it.) inhow is for + * use by the application to pass an input descriptor to infun(), if desired. + * + * The output function is invoked: err = outfun(how, buf, len), where the bytes + * to be written are buf[0..len-1]. If err is not zero, then blast() returns + * with an output error. outfun() is always called with len <= 4096. outhow + * is for use by the application to pass an output descriptor to outfun(), if + * desired. + * + * The return codes are: + * + * 2: ran out of input before completing decompression + * 1: output error before completing decompression + * 0: successful decompression + * -1: literal flag not zero or one + * -2: dictionary size not in 4..6 + * -3: distance is too far back + * + * At the bottom of blast.c is an example program that uses blast() that can be + * compiled to produce a command-line decompression filter by defining TEST. + */ diff --git a/test/zlib/zlib-1.2.8/contrib/blast/test.pk b/test/zlib/zlib-1.2.8/contrib/blast/test.pk new file mode 100644 index 0000000000000000000000000000000000000000..be10b2bbb251759ffdf6da49fadd1a3f137a54c1 GIT binary patch literal 8 PcmZQzX;M+`Z>R?V2c!aC literal 0 HcmV?d00001 diff --git a/test/zlib/zlib-1.2.8/contrib/blast/test.txt b/test/zlib/zlib-1.2.8/contrib/blast/test.txt new file mode 100644 index 000000000..bfdf1c5dc --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/blast/test.txt @@ -0,0 +1 @@ +AIAIAIAIAIAIA \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/delphi/ZLib.pas b/test/zlib/zlib-1.2.8/contrib/delphi/ZLib.pas new file mode 100644 index 000000000..a579974f0 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/delphi/ZLib.pas @@ -0,0 +1,557 @@ +{*******************************************************} +{ } +{ Borland Delphi Supplemental Components } +{ ZLIB Data Compression Interface Unit } +{ } +{ Copyright (c) 1997,99 Borland Corporation } +{ } +{*******************************************************} + +{ Updated for zlib 1.2.x by Cosmin Truta } + +unit ZLib; + +interface + +uses SysUtils, Classes; + +type + TAlloc = function (AppData: Pointer; Items, Size: Integer): Pointer; cdecl; + TFree = procedure (AppData, Block: Pointer); cdecl; + + // Internal structure. Ignore. + TZStreamRec = packed record + next_in: PChar; // next input byte + avail_in: Integer; // number of bytes available at next_in + total_in: Longint; // total nb of input bytes read so far + + next_out: PChar; // next output byte should be put here + avail_out: Integer; // remaining free space at next_out + total_out: Longint; // total nb of bytes output so far + + msg: PChar; // last error message, NULL if no error + internal: Pointer; // not visible by applications + + zalloc: TAlloc; // used to allocate the internal state + zfree: TFree; // used to free the internal state + AppData: Pointer; // private data object passed to zalloc and zfree + + data_type: Integer; // best guess about the data type: ascii or binary + adler: Longint; // adler32 value of the uncompressed data + reserved: Longint; // reserved for future use + end; + + // Abstract ancestor class + TCustomZlibStream = class(TStream) + private + FStrm: TStream; + FStrmPos: Integer; + FOnProgress: TNotifyEvent; + FZRec: TZStreamRec; + FBuffer: array [Word] of Char; + protected + procedure Progress(Sender: TObject); dynamic; + property OnProgress: TNotifyEvent read FOnProgress write FOnProgress; + constructor Create(Strm: TStream); + end; + +{ TCompressionStream compresses data on the fly as data is written to it, and + stores the compressed data to another stream. + + TCompressionStream is write-only and strictly sequential. Reading from the + stream will raise an exception. Using Seek to move the stream pointer + will raise an exception. + + Output data is cached internally, written to the output stream only when + the internal output buffer is full. All pending output data is flushed + when the stream is destroyed. + + The Position property returns the number of uncompressed bytes of + data that have been written to the stream so far. + + CompressionRate returns the on-the-fly percentage by which the original + data has been compressed: (1 - (CompressedBytes / UncompressedBytes)) * 100 + If raw data size = 100 and compressed data size = 25, the CompressionRate + is 75% + + The OnProgress event is called each time the output buffer is filled and + written to the output stream. This is useful for updating a progress + indicator when you are writing a large chunk of data to the compression + stream in a single call.} + + + TCompressionLevel = (clNone, clFastest, clDefault, clMax); + + TCompressionStream = class(TCustomZlibStream) + private + function GetCompressionRate: Single; + public + constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream); + destructor Destroy; override; + function Read(var Buffer; Count: Longint): Longint; override; + function Write(const Buffer; Count: Longint): Longint; override; + function Seek(Offset: Longint; Origin: Word): Longint; override; + property CompressionRate: Single read GetCompressionRate; + property OnProgress; + end; + +{ TDecompressionStream decompresses data on the fly as data is read from it. + + Compressed data comes from a separate source stream. TDecompressionStream + is read-only and unidirectional; you can seek forward in the stream, but not + backwards. The special case of setting the stream position to zero is + allowed. Seeking forward decompresses data until the requested position in + the uncompressed data has been reached. Seeking backwards, seeking relative + to the end of the stream, requesting the size of the stream, and writing to + the stream will raise an exception. + + The Position property returns the number of bytes of uncompressed data that + have been read from the stream so far. + + The OnProgress event is called each time the internal input buffer of + compressed data is exhausted and the next block is read from the input stream. + This is useful for updating a progress indicator when you are reading a + large chunk of data from the decompression stream in a single call.} + + TDecompressionStream = class(TCustomZlibStream) + public + constructor Create(Source: TStream); + destructor Destroy; override; + function Read(var Buffer; Count: Longint): Longint; override; + function Write(const Buffer; Count: Longint): Longint; override; + function Seek(Offset: Longint; Origin: Word): Longint; override; + property OnProgress; + end; + + + +{ CompressBuf compresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + Out: OutBuf = ptr to newly allocated buffer containing decompressed data + OutBytes = number of bytes in OutBuf } +procedure CompressBuf(const InBuf: Pointer; InBytes: Integer; + out OutBuf: Pointer; out OutBytes: Integer); + + +{ DecompressBuf decompresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + OutEstimate = zero, or est. size of the decompressed data + Out: OutBuf = ptr to newly allocated buffer containing decompressed data + OutBytes = number of bytes in OutBuf } +procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer; + OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer); + +{ DecompressToUserBuf decompresses data, buffer to buffer, in one call. + In: InBuf = ptr to compressed data + InBytes = number of bytes in InBuf + Out: OutBuf = ptr to user-allocated buffer to contain decompressed data + BufSize = number of bytes in OutBuf } +procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer; + const OutBuf: Pointer; BufSize: Integer); + +const + zlib_version = '1.2.8'; + +type + EZlibError = class(Exception); + ECompressionError = class(EZlibError); + EDecompressionError = class(EZlibError); + +implementation + +uses ZLibConst; + +const + Z_NO_FLUSH = 0; + Z_PARTIAL_FLUSH = 1; + Z_SYNC_FLUSH = 2; + Z_FULL_FLUSH = 3; + Z_FINISH = 4; + + Z_OK = 0; + Z_STREAM_END = 1; + Z_NEED_DICT = 2; + Z_ERRNO = (-1); + Z_STREAM_ERROR = (-2); + Z_DATA_ERROR = (-3); + Z_MEM_ERROR = (-4); + Z_BUF_ERROR = (-5); + Z_VERSION_ERROR = (-6); + + Z_NO_COMPRESSION = 0; + Z_BEST_SPEED = 1; + Z_BEST_COMPRESSION = 9; + Z_DEFAULT_COMPRESSION = (-1); + + Z_FILTERED = 1; + Z_HUFFMAN_ONLY = 2; + Z_RLE = 3; + Z_DEFAULT_STRATEGY = 0; + + Z_BINARY = 0; + Z_ASCII = 1; + Z_UNKNOWN = 2; + + Z_DEFLATED = 8; + + +{$L adler32.obj} +{$L compress.obj} +{$L crc32.obj} +{$L deflate.obj} +{$L infback.obj} +{$L inffast.obj} +{$L inflate.obj} +{$L inftrees.obj} +{$L trees.obj} +{$L uncompr.obj} +{$L zutil.obj} + +procedure adler32; external; +procedure compressBound; external; +procedure crc32; external; +procedure deflateInit2_; external; +procedure deflateParams; external; + +function _malloc(Size: Integer): Pointer; cdecl; +begin + Result := AllocMem(Size); +end; + +procedure _free(Block: Pointer); cdecl; +begin + FreeMem(Block); +end; + +procedure _memset(P: Pointer; B: Byte; count: Integer); cdecl; +begin + FillChar(P^, count, B); +end; + +procedure _memcpy(dest, source: Pointer; count: Integer); cdecl; +begin + Move(source^, dest^, count); +end; + + + +// deflate compresses data +function deflateInit_(var strm: TZStreamRec; level: Integer; version: PChar; + recsize: Integer): Integer; external; +function deflate(var strm: TZStreamRec; flush: Integer): Integer; external; +function deflateEnd(var strm: TZStreamRec): Integer; external; + +// inflate decompresses data +function inflateInit_(var strm: TZStreamRec; version: PChar; + recsize: Integer): Integer; external; +function inflate(var strm: TZStreamRec; flush: Integer): Integer; external; +function inflateEnd(var strm: TZStreamRec): Integer; external; +function inflateReset(var strm: TZStreamRec): Integer; external; + + +function zlibAllocMem(AppData: Pointer; Items, Size: Integer): Pointer; cdecl; +begin +// GetMem(Result, Items*Size); + Result := AllocMem(Items * Size); +end; + +procedure zlibFreeMem(AppData, Block: Pointer); cdecl; +begin + FreeMem(Block); +end; + +{function zlibCheck(code: Integer): Integer; +begin + Result := code; + if code < 0 then + raise EZlibError.Create('error'); //!! +end;} + +function CCheck(code: Integer): Integer; +begin + Result := code; + if code < 0 then + raise ECompressionError.Create('error'); //!! +end; + +function DCheck(code: Integer): Integer; +begin + Result := code; + if code < 0 then + raise EDecompressionError.Create('error'); //!! +end; + +procedure CompressBuf(const InBuf: Pointer; InBytes: Integer; + out OutBuf: Pointer; out OutBytes: Integer); +var + strm: TZStreamRec; + P: Pointer; +begin + FillChar(strm, sizeof(strm), 0); + strm.zalloc := zlibAllocMem; + strm.zfree := zlibFreeMem; + OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255; + GetMem(OutBuf, OutBytes); + try + strm.next_in := InBuf; + strm.avail_in := InBytes; + strm.next_out := OutBuf; + strm.avail_out := OutBytes; + CCheck(deflateInit_(strm, Z_BEST_COMPRESSION, zlib_version, sizeof(strm))); + try + while CCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do + begin + P := OutBuf; + Inc(OutBytes, 256); + ReallocMem(OutBuf, OutBytes); + strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P))); + strm.avail_out := 256; + end; + finally + CCheck(deflateEnd(strm)); + end; + ReallocMem(OutBuf, strm.total_out); + OutBytes := strm.total_out; + except + FreeMem(OutBuf); + raise + end; +end; + + +procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer; + OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer); +var + strm: TZStreamRec; + P: Pointer; + BufInc: Integer; +begin + FillChar(strm, sizeof(strm), 0); + strm.zalloc := zlibAllocMem; + strm.zfree := zlibFreeMem; + BufInc := (InBytes + 255) and not 255; + if OutEstimate = 0 then + OutBytes := BufInc + else + OutBytes := OutEstimate; + GetMem(OutBuf, OutBytes); + try + strm.next_in := InBuf; + strm.avail_in := InBytes; + strm.next_out := OutBuf; + strm.avail_out := OutBytes; + DCheck(inflateInit_(strm, zlib_version, sizeof(strm))); + try + while DCheck(inflate(strm, Z_NO_FLUSH)) <> Z_STREAM_END do + begin + P := OutBuf; + Inc(OutBytes, BufInc); + ReallocMem(OutBuf, OutBytes); + strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P))); + strm.avail_out := BufInc; + end; + finally + DCheck(inflateEnd(strm)); + end; + ReallocMem(OutBuf, strm.total_out); + OutBytes := strm.total_out; + except + FreeMem(OutBuf); + raise + end; +end; + +procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer; + const OutBuf: Pointer; BufSize: Integer); +var + strm: TZStreamRec; +begin + FillChar(strm, sizeof(strm), 0); + strm.zalloc := zlibAllocMem; + strm.zfree := zlibFreeMem; + strm.next_in := InBuf; + strm.avail_in := InBytes; + strm.next_out := OutBuf; + strm.avail_out := BufSize; + DCheck(inflateInit_(strm, zlib_version, sizeof(strm))); + try + if DCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END then + raise EZlibError.CreateRes(@sTargetBufferTooSmall); + finally + DCheck(inflateEnd(strm)); + end; +end; + +// TCustomZlibStream + +constructor TCustomZLibStream.Create(Strm: TStream); +begin + inherited Create; + FStrm := Strm; + FStrmPos := Strm.Position; + FZRec.zalloc := zlibAllocMem; + FZRec.zfree := zlibFreeMem; +end; + +procedure TCustomZLibStream.Progress(Sender: TObject); +begin + if Assigned(FOnProgress) then FOnProgress(Sender); +end; + + +// TCompressionStream + +constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel; + Dest: TStream); +const + Levels: array [TCompressionLevel] of ShortInt = + (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION); +begin + inherited Create(Dest); + FZRec.next_out := FBuffer; + FZRec.avail_out := sizeof(FBuffer); + CCheck(deflateInit_(FZRec, Levels[CompressionLevel], zlib_version, sizeof(FZRec))); +end; + +destructor TCompressionStream.Destroy; +begin + FZRec.next_in := nil; + FZRec.avail_in := 0; + try + if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; + while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END) + and (FZRec.avail_out = 0) do + begin + FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); + FZRec.next_out := FBuffer; + FZRec.avail_out := sizeof(FBuffer); + end; + if FZRec.avail_out < sizeof(FBuffer) then + FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out); + finally + deflateEnd(FZRec); + end; + inherited Destroy; +end; + +function TCompressionStream.Read(var Buffer; Count: Longint): Longint; +begin + raise ECompressionError.CreateRes(@sInvalidStreamOp); +end; + +function TCompressionStream.Write(const Buffer; Count: Longint): Longint; +begin + FZRec.next_in := @Buffer; + FZRec.avail_in := Count; + if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; + while (FZRec.avail_in > 0) do + begin + CCheck(deflate(FZRec, 0)); + if FZRec.avail_out = 0 then + begin + FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); + FZRec.next_out := FBuffer; + FZRec.avail_out := sizeof(FBuffer); + FStrmPos := FStrm.Position; + Progress(Self); + end; + end; + Result := Count; +end; + +function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint; +begin + if (Offset = 0) and (Origin = soFromCurrent) then + Result := FZRec.total_in + else + raise ECompressionError.CreateRes(@sInvalidStreamOp); +end; + +function TCompressionStream.GetCompressionRate: Single; +begin + if FZRec.total_in = 0 then + Result := 0 + else + Result := (1.0 - (FZRec.total_out / FZRec.total_in)) * 100.0; +end; + + +// TDecompressionStream + +constructor TDecompressionStream.Create(Source: TStream); +begin + inherited Create(Source); + FZRec.next_in := FBuffer; + FZRec.avail_in := 0; + DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec))); +end; + +destructor TDecompressionStream.Destroy; +begin + FStrm.Seek(-FZRec.avail_in, 1); + inflateEnd(FZRec); + inherited Destroy; +end; + +function TDecompressionStream.Read(var Buffer; Count: Longint): Longint; +begin + FZRec.next_out := @Buffer; + FZRec.avail_out := Count; + if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; + while (FZRec.avail_out > 0) do + begin + if FZRec.avail_in = 0 then + begin + FZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer)); + if FZRec.avail_in = 0 then + begin + Result := Count - FZRec.avail_out; + Exit; + end; + FZRec.next_in := FBuffer; + FStrmPos := FStrm.Position; + Progress(Self); + end; + CCheck(inflate(FZRec, 0)); + end; + Result := Count; +end; + +function TDecompressionStream.Write(const Buffer; Count: Longint): Longint; +begin + raise EDecompressionError.CreateRes(@sInvalidStreamOp); +end; + +function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint; +var + I: Integer; + Buf: array [0..4095] of Char; +begin + if (Offset = 0) and (Origin = soFromBeginning) then + begin + DCheck(inflateReset(FZRec)); + FZRec.next_in := FBuffer; + FZRec.avail_in := 0; + FStrm.Position := 0; + FStrmPos := 0; + end + else if ( (Offset >= 0) and (Origin = soFromCurrent)) or + ( ((Offset - FZRec.total_out) > 0) and (Origin = soFromBeginning)) then + begin + if Origin = soFromBeginning then Dec(Offset, FZRec.total_out); + if Offset > 0 then + begin + for I := 1 to Offset div sizeof(Buf) do + ReadBuffer(Buf, sizeof(Buf)); + ReadBuffer(Buf, Offset mod sizeof(Buf)); + end; + end + else + raise EDecompressionError.CreateRes(@sInvalidStreamOp); + Result := FZRec.total_out; +end; + + +end. diff --git a/test/zlib/zlib-1.2.8/contrib/delphi/ZLibConst.pas b/test/zlib/zlib-1.2.8/contrib/delphi/ZLibConst.pas new file mode 100644 index 000000000..cdfe13671 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/delphi/ZLibConst.pas @@ -0,0 +1,11 @@ +unit ZLibConst; + +interface + +resourcestring + sTargetBufferTooSmall = 'ZLib error: target buffer may be too small'; + sInvalidStreamOp = 'Invalid stream operation'; + +implementation + +end. diff --git a/test/zlib/zlib-1.2.8/contrib/delphi/readme.txt b/test/zlib/zlib-1.2.8/contrib/delphi/readme.txt new file mode 100644 index 000000000..2dc9a8bba --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/delphi/readme.txt @@ -0,0 +1,76 @@ + +Overview +======== + +This directory contains an update to the ZLib interface unit, +distributed by Borland as a Delphi supplemental component. + +The original ZLib unit is Copyright (c) 1997,99 Borland Corp., +and is based on zlib version 1.0.4. There are a series of bugs +and security problems associated with that old zlib version, and +we recommend the users to update their ZLib unit. + + +Summary of modifications +======================== + +- Improved makefile, adapted to zlib version 1.2.1. + +- Some field types from TZStreamRec are changed from Integer to + Longint, for consistency with the zlib.h header, and for 64-bit + readiness. + +- The zlib_version constant is updated. + +- The new Z_RLE strategy has its corresponding symbolic constant. + +- The allocation and deallocation functions and function types + (TAlloc, TFree, zlibAllocMem and zlibFreeMem) are now cdecl, + and _malloc and _free are added as C RTL stubs. As a result, + the original C sources of zlib can be compiled out of the box, + and linked to the ZLib unit. + + +Suggestions for improvements +============================ + +Currently, the ZLib unit provides only a limited wrapper around +the zlib library, and much of the original zlib functionality is +missing. Handling compressed file formats like ZIP/GZIP or PNG +cannot be implemented without having this functionality. +Applications that handle these formats are either using their own, +duplicated code, or not using the ZLib unit at all. + +Here are a few suggestions: + +- Checksum class wrappers around adler32() and crc32(), similar + to the Java classes that implement the java.util.zip.Checksum + interface. + +- The ability to read and write raw deflate streams, without the + zlib stream header and trailer. Raw deflate streams are used + in the ZIP file format. + +- The ability to read and write gzip streams, used in the GZIP + file format, and normally produced by the gzip program. + +- The ability to select a different compression strategy, useful + to PNG and MNG image compression, and to multimedia compression + in general. Besides the compression level + + TCompressionLevel = (clNone, clFastest, clDefault, clMax); + + which, in fact, could have used the 'z' prefix and avoided + TColor-like symbols + + TCompressionLevel = (zcNone, zcFastest, zcDefault, zcMax); + + there could be a compression strategy + + TCompressionStrategy = (zsDefault, zsFiltered, zsHuffmanOnly, zsRle); + +- ZIP and GZIP stream handling via TStreams. + + +-- +Cosmin Truta diff --git a/test/zlib/zlib-1.2.8/contrib/delphi/zlibd32.mak b/test/zlib/zlib-1.2.8/contrib/delphi/zlibd32.mak new file mode 100644 index 000000000..9bb00b7cc --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/delphi/zlibd32.mak @@ -0,0 +1,99 @@ +# Makefile for zlib +# For use with Delphi and C++ Builder under Win32 +# Updated for zlib 1.2.x by Cosmin Truta + +# ------------ Borland C++ ------------ + +# This project uses the Delphi (fastcall/register) calling convention: +LOC = -DZEXPORT=__fastcall -DZEXPORTVA=__cdecl + +CC = bcc32 +LD = bcc32 +AR = tlib +# do not use "-pr" in CFLAGS +CFLAGS = -a -d -k- -O2 $(LOC) +LDFLAGS = + + +# variables +ZLIB_LIB = zlib.lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj +OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: test/example.c zlib.h zconf.h + +minigzip.obj: test/minigzip.c zlib.h zconf.h + + +# For the sake of the old Borland make, +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + + +# cleanup +clean: + -del *.obj + -del *.exe + -del *.lib + -del *.tds + -del zlib.bak + -del foo.gz + diff --git a/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib.build b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib.build new file mode 100644 index 000000000..e69630cec --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib.build @@ -0,0 +1,33 @@ + + + A .Net wrapper library around ZLib1.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib.chm b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib.chm new file mode 100644 index 0000000000000000000000000000000000000000..f214a444aebb20950fb3e8499b36731e1f12be95 GIT binary patch literal 72726 zcmeGEby!tR_Xmt0Lb^-3ySqWUyF;2oNq0+kgMffYgLESxDJ4jYNJ^JTHv%sx-r#-v zJooqc<9Geu_qyC%`^?@mpEY~UXU(jcS?6pdRg}fR004mg^$Bu)%1mlyL4X4QNEaZU zg&sr5>2QFIcf>23$bY-P!QUL1KN5iJZK}ffiW3R5Bgdsi#SjndZHoZ7pFgTx{Kvz zl?C`=WYS*WsmLox3SSrcy2a>U->NFfT;oBWza%PF`f;lwBm?q1PBTK{x+--^IT3kv zWsrnPVqY0p22wFe6GwAd19NMT#CmhT0wib#Qh6aMNjYT|ki;D7XOGYsNY&K^9UN?o z%ncmPoq;mu)=wO6G{*aFfr7n_EzsW4?OK=|9Qg(!4Rmv{u{Zup4&xu0LMrw^AV|WL zwQsr1_s9JrB4XfZ0FoHNo#>AC4@p@ATad(TRwb-|l-$z;f)Is4#Ky?U3TW+k-2@wJ zdNVU4khpqL-+b49mOKH8pXU?Axt4I$k})@=7c{m6+6$Wjjh;9-S<#z0T3Lel_6kK{ z(ESI5s;#ksBT&!A8E9{5V_>Yu@xs_Wvg1a4XW~9`%&`_aeeJ)((#LPDYM4 z_P1bvf^b5Le+4t$qN5&#DE~W}`4*jo5@tpG`?_U;R)#?PTaA4`Y7~qAN1&sbjq%T> zWj@XEAo#1spY)0Yt%3FicWv5~3zH%HFDNCT1JLn@j{f;lA>2&=1^aiq+%n<6i4ckN zzsTKk;{Vw>0`q^7yX^=5y$_%1{V#H?x9w}T45wlIzqjv}X#aBXD6{`Yp_+lE6Y%yC zvAiK_cU|-!MiDY_0MhFjIoaD^52PO=0n>~j#w7n)tM4M;$Bh3eRfG)Hzaa0~Gw=m` zs1Vz~;Qxb71J`(?*#1}9Te}8M!9+6uud=tc4Qv-omi%93Z|xgc;}Ido`oFdJ*2aN( z^3k;aM(sU22kdBss?h)UNBzUU1eD1|h%o%0g>FYzz#EiM{{OqwtqlS?6~amWr9oom zK+B)rBw)xPoR9jy>-LME3J7$1rTMP{_xx4B8EuxqoyY&}(72s(%z?LN30Ou87rAra z|B(4bBfn$pD4YKZzNd|U3Q8pBf8povn)nAnhqK(dWnmj*pwacbW_&kE-I^B!eDF&e= zzkBj6o3~FM*9s%~T{Et&W?*UVerwo}d9M&^{NJ?pzHvh~C_>#H{s#2jz(Kp%;Y`0X z@Dm{?6BD4l@?Q@N9w7}8yj%Eu9}3^ukhlI#J3|f#Lu`Imul>!!L*B{pj=c-S5S`y4 zuW`RxEi}+F4Eb+k>_&rsc--J>v|t0ge>Pdv`Fi@j?J1$rUSY<+!QA(b!HrIlD!<|P z7ylFVO}b9F@p~coG=qg7vHB_q7h1r3{n#+fe>h8z0>mi+=#_ zX%duU7QywmcK=kGfX+b6A00F_2Rs_*9zsc&h52vBsv-z? zxaaqOLHvF7!SbWlux6I~D}CYrCUa}Xurk*BEB#+Y{?RW&zi8fH>HjD2txFF*a=X9M z|4-;!FBN(vbAP4(3;Gueg|?vFU+Mo1c+XN{VO%*LcisJ$K_+2feY3f`rELr zJe2%;+xxr25HSWJ1O5n30L~7!4rT+I2HFJ51=0yZ?STQf6qqY$0th@v6o4OK0=U`# z(?Z#%dGKq@!3>E)vb-&IgQ7?o;=7W_=qr> zNUgi+?Ow4A(Aw1TcD)h#nk|C;w;CzfIGF#4Gu%WAB0HW$-1E`*YP;h!s!S#M_hj8* zgxr3T71aY9N_}U>dv)CrA2rMt#dbI1e!)22Z$Q*%iwK9`QgzQfQJXr6F2AkqJLpce zXn&Px?7JE8?y>*quMx{0VfuHY_qWJf?-jA59i{Lu&|B9PaYYk}@H?aZG7ch=$@^7* zkGeM!B8TPM>3-Mfzt1s|5nQqE@PBor@4d&jfGZ37&XGx4{})FVlcay&k^L5X>&Rjv zaql~_zo5T3vY33K`;P1{(0xZ1Q|25>e&=)k!hBagI?g&=^sZC?Ec}NJqsO^|#qK)d zPuwqDN2jyg_c?c%drU{qJ}t$&v&S{YhF-$JK?G>%WcvN)yH>F=tRbQ|p}HR-xx0dx zdfYJazlq;0_T)|EO-%lZ4aFwAg(%#)nD630PzpBY);E*PkEdixhA8~fCL8)6FjdK) z0gu>1tPrWYF>|jfRT&#=)7y$FjY8z^hQfD{ssqsBI*NK7EwgmHS#{nb8<|3M?iM=V zk!siBwC_R68|M+*fe<3}t4{y0Ma&+4@T0rs)=ee9*dgYvQ7O;eChVsC@BKLDR3}mW zZY6XR_!M92`IrQfOLS5E*Rk&7G})H(ik4)Z7FlAp$%Y z4&gf2#?j;^r0_j6e%mn^_g0`xVT42e~2LWd0%_zvdF;1&76%6hF32tv=dGj!U z1uoUU;;%KbzUf2&LnwxS1*_N_SUZ^5*jq7tSD%+$?|%^S;1CmL=Hy~!q~j7{VWMMV z61lz-V&Jxr-`6Pf_{Lii%x zdZoL)i++*|5t=&fa-*N3>gCP@d3pHNAOm#Lr_Lg7m#Xz(9Ql|at87Hcm8)v z@Si*TA8W$9;J}}&KMed~;12_T82H1$9|ry~@P~mv4E$l>4+DP~_`|>-2L3c!ufYge={Z>GIXM`auggilzhiMD^ZmVvAHsn0 zKJ~2h7aczvcilR8z|YX(O$-PC20*yZxc3480OC5w_?Mgq0BC@$gR!*)(9#wFdHt+1 zD5GMy>-6Th<_bxLL|OI~aW%-zV}ict{&<7q_VSmvJZ^r~@%Q5f_m_%4h5n>}82H1$ z9|ry~@P~mv4E$l>4+DP~_`|>-2L3Schk-u~{J)9;#M@W^64Fidgau511pq))O(ryd z1lkJ<4U}b!vlFh=$D7i8MMuk2Nz7V{XY;j|=6tiZHcmtQJY)|M{NXWUF#tfqtS<@y zkOZWYRRSyJ)PzW-rIW-?Bok@f2oou!{V6E}wf86Bn|cRo9k!a1=<6%bC$jZADJ=&a z7pWfWw>tNp1R$Ovql(VwWf2_s5U3IgsvhL#TSH^So#=o{Uuy^+Qqys*;DvUL}rA?=4`lbR=jsW0?YvR*h$HnNhp= zC!izu;7A+DiZ@kulAlK{n{*^;+WBXnvVm^`j#IMvXU-V}_qao1<69ICjx z#>je?dOT5Wl|%`3vbEPHG~%aFZzYFws0JrvGib&2P+KG9gm@|Na;`dR;@hXdF0GoZ zA-H|QH*e*41=$Iq5bI%HN<7~G#@%@RB7i{JIIaZ}5Wwy4o<;eoy+hDvrhjIDL?wm@1uB1Q#CKL+EnX#od_o5Ll)IMaO z7NBj&@^Kd;)<%OES%^J;dru5(Byz|)wNe231+*1B;m&Izkxf{~q>@M^K5oRE!sTob zc|{J+dp9AWy9VYkT9+9Xs~h za7ux3s^H@U1XPuqE^Qhl@AX5bvU0-YlbYY7u#DLoD@_$+y~NzrtM0>7+1`o^!%<4#Gz6nx%!45)1j#*6H%w}%lL>bkPU;E?AJ8F+BF#1h*)IhVyMi_Ov zsP^M0U`mpo15%jKwLnIhv>I@EEM%1`z#gA-uZa|{w;0Fa<;p*AlslXpj&U`@7sC2t z^zDl(eNUPt;1!(3LTitPAQ;BOW~318lc{z8PH}Qizn}}TOCKI8urso=eH&5)*=8`` zp2~o#l&9$#hnp<9m0A6^0!0mYp=~A0p6kv&f``RmG&`p&3S1xA1q#Z&mWDQ+e8$QU zdYCmRYx5Uo_^3Kpt2*gWb+llW=!(}qid*e*;K%r3yXT@z9M~6J6s4W)yAYFWe5HLK zLzt|wA*)yYu{qhsS{D>18jm#IH$G*d<0Wc!%;ZV=R!Zbb{^7V)aDh~#YlpjpjKM9N=; z>p{p}tsH%-GWJ_W?06|`VM8Q3<;UnLcV=dbQ(dHnG(Sljt7YptrcYv!i*oOTH}{dKWA=+9*g{ZYWJuh2k-7#a>5t$bF)tT%YE zXknN}yshg~aR3ihYrf2JAi1;`U>8O3G~wXHJT%z47}=uULl5)|GbC{@3l!y+B2*~f z5DjcU3lNj0L9LvJs2$yYo&PnlA$`0mw8lE44re*ay-w$)@TQd*clNAR(%5uPdB1zi z$VV@;e2am|gwU=bi3Ahc2-#RQ@Nj4ZR|M%yV{F)u1EjT!9~IyGxH=6o=bI!9tM4V9 zbj_g>xz2R!1`{swDfWX?J_xn2!x`6(1sn7`%cIC}oA8KLKFZ6G`1-{Mb%Gh{twcVN zq6VA;DyiF|ZA@EJ=2F1GleU)erF@D~9hw9hVXb^lDkhymJIUFHVbQAc(AH!-KEV8w zAjx)Vwy>U^Iw=20(<2uf(23nLxb!{&gdH4nxP_*xYF?fdBUT{!B>#)%AdnKLLoAd% zF)T0&Lw=ZSZHt59{(K>Bkvty(DpM`l82!)rC-3lEYU$}o8c0{qipkSGIh)_p6+1p# zvQ=^Jkc`a9Sh>;&={E<<*3Q65XH(xKGsk_s8o{X6xD&4X*)r4CLE#*tde3<2Ftz&J z-bRK2D)TE^O0lz+q_}32BSXH1giVjkV-(CZqm^v#z3`3d>Q)Jlz#WZ2C|%q+1=V7( zOL<5p{(S34Nr@ks)(@gEk0mIzP1K$3)Az#HKgrY=yXS2rUBJ+Y=+H1-R5Fa~QBCT! z;f*{V=ue75&_o`g?M=eV>fF=Ze+=&v4p)Cx6@aLwjlc>kTCyq1q@mr`ZM7q*a8^Ly z7rz}o$wn8ZUHU<+Y8&|JQlkt+Luh{UZ0GGW=pkwJ@fV_I9S-k7!Cuo$&2Vpl9RZKd zRQCZ-s|f59qfG4gNx(e7C8Y721+6zf4~s=w7U|a_o6;>swO!S`4CNDZwO@EKZpwjQ z@Pb_6ThX|78nr(WG{ROYB;F7^oFX=zE~dK9y4#dXex!BgnaRaZU$J?%%%?&@hbFD_ z%Ej3Yq2$%}j60QKxp?1@dHrs(8ZPvf(sVTU+E_+p@nQTY&2sr@D^;-;ho|sPO(8yoxcfqEqX?w-F68l>x{*l95$+F#fzj1+VJ-K+ktL;m{t$ zn*%I&+651%T{a&pFy@uVK)CaMp}j?{^FkcEfLYv<4xTgo(Wqm$#Om052eiCYmD5DZ z&ijs8rrC14S&PxVisY*Kk%D6meU3**RHOwGs&qZsrpG0M*RMk9!HROcM%3-mu)-(XZb)E($w()#z-L!EMb*e%#1Z&iG(gpF+| zPXJUKk3eY3l_H->hMO+$C1jVgFKG1?m&zkX*b&7{SCJIYlb(0r-{B6Oe9N(5)5M=Uak}sB*b)ZU~ghv z(IG(iUu5B<3fH9T^vKy~ats%hi{$1Kr^pY|L96c7P4Ov5#}w|2zlD{iskUo=IVpM& z5&@Ix^_sV=wO8TrX-WhxY#pk%*a8z;q0z?Y<$dMxBn;Zozj{YZV2o7z&>-DtLB`*fMufc%%(P`up2-<26ztjiYl_%skr?=WwAIm-DJTPl3SZ?3yXxi-;#GI?^qq0Vz>4 z17s=BFD^xg9QS3XB!9=mS(}0@iPiJn9F_P{+q@xoiB?Pdx_epH5dJ=0UgN)10zR@>e3E?b9{{ zu=7O-DJXpk$DfkL>3b_qCwqJZ(UJ*8MzM^gggLS^N`54;Yct-#~H$Opm6;`8YGxoQ}nH}tDm6C{>AWzyOt zc*q%{(5GjR-L*c-SM-qC8rWtpJ}eyPLfs2(;`=O)&pfpP?+S}`2*d-mA)Gz(@Ft?R zt2G~BJg^gwVe2)myY~)kl+hL5HM6v*|CE5I0N*l$uUwYfeSNjeS z`)!3Mh4u&uQ#rhcI;Damwu(b;3wdYGeE#~QH2~Q}43<5R`+2?}n;|>zyo?cv{eTw- zriS0vVZYvMCV^{zOFyle9<$auzW9~f7(b#M^>`otrAN#T%&-+lM;i#CcGV|Kq`IIT zf;N?5q-`97b)<>Z5tBoK^NWxKcbHM5957zsdeFKAo1-weVs;pe$jiL8B7qK@+Se1& zXa+-)2$2@;Eb2y4lmv>Y)31$JA!c467rmo)o3P%2aapVL?BrhZdYJdl$-%C~;;j&o&8+sIuC5Hud||g|)0M~D+^e+JPOja>HqYSdkF2!= zgGe!}hQQ_+Gkdd(J=c=$`tfz|1&_XOo>|5>oW#%Vf*atEtQXbgyN&#ESLSPS$QOmq8~BiXU;z6*+xu=JQSQ+JU~{t_=sVL>ii(V-}H6M-2+xf>cp> zIMCfb4tePxIM{PVzTgVEX~XBfSH@ArgQ?rgVuj+KEw;e1sYH^vCBEZf@jht=o(vh0 zn~>wHx`X_i$*#mR0uKVRmx_9rR7y)Dk54veWKQB*0V(P+L<65F)^;aRpkKp|uzBQ# zo}#0DW&>}U>Y9$o;AA+UuF9WZo{;{aJKq%kvUXhy@=*89D=Ub?a*T7eU=t2h+ju^F zT_5)2dY8%7pe$0{d=*6%?4Gze7XqdRlwH+q2?g_SN?906dm++;hlki%IqQRNO@&Q% z!SKZIOzqvXZ3rpRV5U&ucY9@~&?Y0Necd9wZF3id>w>~;lKJf8M9mK061%TP^D8Kb zef?xC;PJJB%t}etmuBPK6ZAmAKR04Yp&^}d-hxC0@DY`!5%Sq1AU0k}@zaS<{_efl zXBtzKcG?TAhz9f?RcZV09+=C0U0L^`zEC%$(&r{GWIUWFL1Kp=f_aO?8DHW53I-`u z4V*tDLS-;4uBl^929^3*t!}ClMZqHi{2n<)AM5OlG$KK6{1ii(a#N**5Ev=Xup_*I zEX8BvB%cD69?VhC-nAo5&*$&7D^H~kO6|04QqmFHP9^o}rY89F+v6*7?T|%yH4v}_ zE7|Rc_i_q_AM$%n)CxcyESmRZrjxoq=Pt^|TMQqH9t&kO(dBN?7O_MO`NhuVg&e2`KMd?Bt{8q+~=86vNUk!`z}G?0+n9sB%)sDV^{OiS*9!yH7{@mmZ){U%dVb_5R?MpzGt|H7&>z1wlHDwoin!&tU!a z1pS$dTb84Jqm{4~VT0ck=J#;p?w26bGjL)w$3pSqz17UwhJQp&f<52e$)-SwkIoJw zl3+6_my0ke)>r#ck&~DB_0+Q~Vzkg@UHqpJX6b<>II!X;$L}{tsz%|S$N!8RZ3f;J|*8y zv-j+r-|k1;Y=AN`lLUfxzTlPCpSoT%X|6@lc?;IY1ayVOOgT^2PUUS?)o#U^i0_9i zTu0o-kv;+dSXi&KzyNDt1QPnyF)2_WG$5e-t!3@@=)yKWI$x^$+nv9bmT8PRmo~bD zTUb3gZZ0YLI@35=QnR}on^ZU%wOiL+*w_`uz&o<4W#t;GZfYG72->_;5iCFmzHkm8 z0sxSiz_J;Anjg)cZyn8SUCk)h%|rk-s~&!~t{r>w^`p5;&Wi+D79=|DR7aDT0%}$$ znXClJbk}rfKOa!P9H=m6P(q(aKK_8{y+`dCnBfFzgtyO?}e)*?u*m%?G=5O*z`2edwRd!QC4AjE(XI{AQK2_nUv53>yY}6 zXY1or!u*R;p2vY6(a9ttr!Wah^~>vqHMv#|;cYFG!>CPR>D$x7>7(4Vy0WcXIZ`{L zMdOi2Gu)UBX-RrtJW^m~;VGc4ww$%#wNmA?CnLF%QyG~(_IfAiAJDb83#6H<)E#XQ zuNPlD*h$;|@vFy<+50j@lULpkJNe-tbg#!CXGM}dThN0wY zd0vvwsyF$cYcB;lFx7re)zbU6b@2G|M z7#N0IF?1Tz^kwo`N`MlDJc%7H?5U1E970xI&R&U>=N~t!|BzT>?G{ zi2LohH00cJBGqih8UXLB-)vMXOm3E3*_x>%MGb6Y*y6F)mhTS!iL>*b#!5PiqhZVI z$~m()Do1J`!oH-CrLC+9)HTDH#iJkwaWSOy-Fjc6o?NPaY;+0=vs?I+Cm=_x2Z|CR1tz2#D!j>Ky_mvG8YTe#^)P^=aWIVm1W+!q?2PpDdy z!?>rDk1u3$O-du}p_t;`9-r~}ifx7sI7ctJyM|jq=E%Y+ZHXdcB zD^_NV)L~*WNzzaAmMIcvsT0)5a$murA&+jb$#ZTbm|7gO7-y_K@f>_1uX}=w2i-cq z3Pgw{kejSq7cPDurWz?n7QAO!Up7fOsNC)kOZ6%f0n7IE+-wRwcoT0G;tFO) z-D^=T48wu}uwoZAI&#b^nC--lEY|;+K+tdXLkEM^s;5z6fD1eq!>Mln*iy&K(k|_n z41HBF3y`~EyqV0J<~){HJ`eWDtFVWNBZG8ao-{tJXhE7?6wKn9IxDDEEZ>{D>*8Jd%etAphHkuB|@oH-*n(2lBVC9(vdED#>(+ zPWLRJ5*Ngw5`y@2p;3Pe_UJ>x(r>Nf7auUlUg8-s^P41)A=Q=dZCpA!A6hLDt+LA| z#*1MGMjyYYqYw){pTOjse_3HF?t+M)T&}IaG?+S%vc0mabYi&Onw27s-2Ub)D4cg! zv2j0;48?)7!zjwIEmYd9mTo6&9S)IGqO9jjw-v)dq*XUur=Nj_*7SNoq8MageL`!0 zvh=ahxC!Zp)kZZU0?{*yOkC1cD$Ycwrn!BkS6oW_jJcl4!AzQ4A*QX05lbN2!U4Fd z=-qF@_K4l1bn6V*o*T-okqm#pPB+? z{(?uujG%lulY0g%vS13?ZExpbCw;v|ZPVT!z-7_e`l*Z%Q}ihmEkjcw)QY*k5@?3z zgSF{yM+-+$;8+kBO9(v^)9~_Wh64SDZUE=kgiD%|+x$8vZb$D!$mAfnCLfV2pPBka zXsh$GcwRb!mARyeN5ckNa}F3e?TU=1Q5kc0lBQyCI8#`ON-V31H9%9|#x_cZEj~tG zAH2g0*bA=kBxYBc2!ebgIWLGFNJd8Rn9iJ;lFOm{NFZp346wiUsI0G;DPY={^i4cI zI@8<-nmOwDp32#z_uHhSC;IU_M3&tvexDsqgxF3h`}BkkEGDu!mx;D(`bC>Q4ahLH z&4+doE0`V5H80hmcXz>?vI+q*w&HWnTiQ#4-y~r|M7$m)BxS&Go6kv90$D00N-P3< zz4?s;&W$~kK64y%dKg*grOr|DLA{}Ltu%&o_i1DoDsfWT4zh+23WO)N;n2cKWIDmi zUbup8~!V0J%e5xsHP@-#daiW)*n9C+tON1&Rc~%Smt}T>mS- z?vjE;;;Zfhe{&Kz#E3o9Md^CLGSqueKlR4g?6Ad0d{W}dC@;3A&ex~wqAx^0=O+j8 zoSH?vieTcMugR+RL8b$fjsF5|>nv% zxEn^)8#(2^009s{*V&13z&H9 z=*@0}=T0=^)#^QZHrcEYR>9P=P#Zqx%0ZpZzE}04u)l#zd(QQw8PWQoedN2vehh{S zbg_5OM_Va2DOu)11^5`q*9J1I%fVlMa)DlWpWt-{B_+(zU#IJ&lz_?0pGne~AOl^; zDN_$LN%cyYbPfu@dz@t77=x}Gh-#|y`G`(vf%8`+8erGxC=cKT}~!RUv|^lX+J+VF^7FRJIUc*hvsNK$Y+Yr z=`FWwRA)%e9qe-$9`q;_)uzR3ww`gPN>&PI!A9s(sb}Xso%|H9RZ!zfm+0VSyccH+ z!K)XJRQMZjRyZO+;} z6#GxzQqxEQ{VY#pc%R3A9DSYV;(2jMiErqwYZM zTvm6f1&%lib=g>dzUEcF&^HkmAB?!3nf&FV%`$Nk#7C}L zgxtM7h-S1Omi*i>+54-v(JIqg>Qs8ss2T9EUAi#=E!HnONh1p%KTxh! z_o^5o|N2P;7Y{YgQ{>@=pD>_0YAqLy^#qgyCnmqA;4CiV%p5n_9-a<=x&XtMTA>0~ zfhmX`Hq#5mOPMxA{%T|-)*AEyAjfSv=}R4)-(V>*;d=l+7kj~rRf*Fj*fi?8@aC<8 zUFq_9HFaZ`*{g>PxSg7!JS{SkGcbNNwW$PWae-szqRcd*L+Xe$g#Wj~c{cr$J$g#||a$w_zoQDn}38gsA#hiNTz=exy zcJRYD#5Uxrr&WOn$J(nI+2boL5fAJx4Ij&cDxxvtKC3Bddzv=&DpI2-jkw64qgORN zc$m=nL3+khHT^M(vnTp7!3L%JRAUn-odw!^%RaNL=Nyy!yX+9nm_kU44x%7X=c$S& zY%7e`HA56^;uSA2O1_HM2n{Z$Lt+Yk?86qO;A!Kw4Y8k8^q(AT^;FV!psmj0DiAl( z7Wo#b>?Qu9`+@MMN!nFQk}1xx7$rwbLOe)A#V5ua@a4mvHR0|tG(2Mm zdQ!tsw~%b}t<$!DA`IpY>xEnx663d%D%!2xEpv}kPOx>VQ57w18LH3fvxvEZ6NJG| z3M+unT*e<;5YKrZ0!<7G>3LqNpoyl6K&`|$8+L+Lz+oL|6-I439VQiuy$)BndftMp z8m#Ee2SvW!;v+kt@%*FSGpJ1eWHiuc2+ixo^V&hGh6*I&vdI+B-&Henmq^IiscUY2 z!$?vj{IJb5QjZb!HA~n%P54RpWYMrRTCGl~H`_VAj7WulF;G)6Ed=rdCG~z zxs?L3y*5#mq+|(wzmfLQn#I2y)XUS-;RT zxKe2?d;DaKx=Hywz1Q>vfB~a#UP7n(G+YA*+Y?)Ca-f%GG~%2P>nF2>aI@Ly4y5nX zsinVFN8qb6(g_#}_@c3TP&_0ywbf0t%zTBtEJU{5Z(O_?;J&pr1jF_~`6*aT4>zFNJ%Y8>&WmbBO%?!Un`jw`rG}8sB%ohe6 zbBev?3Gr@gmI&03t)mlNf*Ok<|8Nj#;T2^KY=TApTsc$5@sZ*4i-7Q_+>Zk1#+_#} z^HERFrc#S8-!*t!&f1uP#RiT8N-f?lvJ9cGFk5nz)u?FE@Ml(i%1=EYb01v`KS;q&H)QEwZ|;4l-{Y0H_h7?d#(eWX zjsKRi<`y2Dlg#PQy7^3|_o1t7p*E?=Cc*RWK4hlY4mcQQCONBp5_(bE%lJBSB{|lC zx=o==x?WSWRJJS8py0i(0Joe<@fqF`m;6thPkWMwFNh3mJ3J%`%_Bd^usic|O36xC zWUmCdlyVuO`0&xIiQ3T*K;Tc2S@<7#w8ZbfA#b0qf!}1*j}r!M?jqr!RUzcYJEsFD znO#>H6gr2T;V6MJc>HzgQ`r^KVIX}?+>*GU@PMMc()cCHr@~kaX>6+)LQ#_opFBk! z`CMpGYdf3?F8yh-JT3Pli<~sLJ>oBn>WcOgZ=-h%C#9B1!E-b=Uc8nJL-qVDp``D2 zWg6{sNa{X2-Oc|jmZI|=4Y{?}6P%Hel5@@ogSH}rCmnq_V=_&ZxI_`VVr}Un9k^=)>b%#rc`Pr6D!se2|f9-X&6=t5!Sl0V+;$Re8Au!aFETzne2n z1q6BMfq<&}ER4R)ZVCjQ;XDJuYnIQ|XiLM!s=}oK;m&>Q)TOve#(n?B#LBVFS_f zq})=lXaLeyI0b+YnDZGx;5H0m^!!jH6565`;nIu&G8J%MDbwE?WP z!nHFz%Y)7hjmZ=9Z?aCnKspZtE&u@Il~OYRU~`TD6x2KbTL>D`7is52yBL9$RG?P1 zuhZSR?v&1yWA@B?AZ4a;%7$*-eu~eFzPECEcejKhu@W!ubDh;dS9jf;izoCY3qfUr zwI|?#@o%(g2>^&Z(zv?-0dRns$y^2^oX7UprlYNyt*V))9(mfa{dljo+^4>b*OXX| z^-~H@cIZe6LVduVdQ)8@Ed~uO2`vPLiE@xn8Um#uO6CpXV+TU(4FDzDrvVM|0i<|W zF}-qIJPpOx1vX|r=Lan? zWrk@FJ8A{nnrR1hN4_FCgod}IN~(tGYwSL$D&)Ym$2NgSYVIj2!2$o`xy@=GP%-7j zh5SYn%dfUJn+R6>EKZcx#ib#Q}#owtZNV&s)&e&)QlB_KmssY0AFq7Dlh;GkuRPVhCz^b)q3{DRlE8|=TZPo zjln9~$nKn}%npe#$-SGGq< zuA1#U)^I;K$nc~9=wgq=WVCWvmDju>KJc|-e=?i-{q}+ zD1<_NO-EnM4Z4oGmrXaq7nYJB{SdgV+kM*b*87Z9)u;in_|j{tqqK=w&Yf31F3RhW|d`J?28 zOzzY-EKi?fMX2~3`M`a~8tFH7hpGEEckig`$ut6x{4$CjmxTEYLz!c|rS`yQlM!OkS!6 z&%Jn77(OTL^6+ElHr=L9^SGs%!Je4&hbPIXnYpF!3rD7|?A`3b#orbzN1Mn|MoHBK zmy|%Rmwkyt3vhW@Gbf`MDjIzZ!x#Q^IY75krD!(x6H2z!YaMT9+bAa~Hqgp}MFEu}*)km1lIMv5^2`;0Ce`;wbZ+u*0)9?M@DS6da ziCz^2)#-|G#o@8N@|2gg^0fAptaG?I32}D?yUmhaw^b(y@lyqsD~aVHo(BEUZ^i=G z-$0`d=?p#@8+fu-dM4{jdA^t-EY5a<g3?d=X5U1J@mfoh>gdfGr?3Wv7)4k*m^w$YcgyNw*4$~V*)k)dyrF@Af1FvkaL zXdj}n>MO(=qk^{%xe%e~v%yV$em;1(tjBFtFwY{3s3KnlfmoHTB5mh|wA*Cxa3u@IbHZ9TLnZcjP1#j%N|pQpwTVS ziJS|JT;-W#!qsuaXBZUf0%J@tcbEtK7&%X{mp9-T1sFw=srhn=xbWsUgr?rr*G*J+ zJ+ICq8#Le0)HC6H9aLuSiDbt->LD0Lo=r*A!P%Y#yXy~SogvVAYW$KBTp12+n&<4#;QY@G@*kGtLj_WBe`8Z(W&F@~ z{zWu2Ys?PTq5VKFC?c$8dU-#66kE~rTzA2m0!xI;e_r;PzLk1hcqj7X3FC0wl}PS% zm;62UruR`239S1~AbJoCzO1m1OPA_f4W}}{Olw?J74}y?k>3517c&|gXUV|zFumJZ z_}$U7lIDlcdE<*DyF>3zA*>jv@|3dW(e2D&wCs2;>@-q30r$ze_20wn_%TV0-wxZ~pfqPPKfwjl{ zNa?KjDx3l@1`|?gd+eMRS3Wf)2K$k7?Pdw@n~bp#+(Rrk^$V!{N4s7xx3@t z93hkt&y0gNG3f_)eLq0vFN+AdiAHUp@S?DNtd>Z9)s-!H2+b79fdpwkWz|1=$g+s7 z=Lm4FU|y3|0>h2FOz+Y{;n?LJ+khC+03K#5B&lCoP&I#+wAH5MXX);nR!@=v^% zgL;ny(*`YTtm=CGcfM9MuNXY$bUxZRQf3fQ<+0x4Cz_<9aTwD9y&6!RAjGdk%U>e3 z!7|1p1AE9NTMA2Z>X2crMo8O0@BZo2uqmh}+vv6)B6>H=Qq3E@d6`G98%U808lLsRy{2R!zBIcX3N$|2((bsfL1;gNMBtc`9~`L7~ceO(JSh9udrT(pD}Y z4d5R;@;j~vJF8mMu!rSDzf?0+8N?cWcG8=j{HamY-8I`jMPAIY1-+C+NtUi!$=!UPGqz1PuMvpU0TOsKk2{4{h%=R}_0AmL5> z$!9OLQ*@D15|?0T@Dr1tE^=Dc{Nrc;rRLEw6L6XRg%dSq+gh=+OT)B0j9EGelj z2gNN~OnwmRrAzP@t%)y{fCme-oY;YgDIzlWfD!;3CarFr6x3Z`ueYeG>3Xn$`@Hgz z=LI0YH#YiwD{NfI?h7Ujl-E%*L;_-J5uOGg?W~`fRRF>wE*(rJhHKv5v!P|1^F}U} zbYHFp6C7Y26BpSmY0Xg=dqIMJ)hzKUqR=zg1Uw~-#--Jg;$;ap!4G1rsmgMxXAUL~ zQYtEqBcjmH#>%e$RRsS|25bZX4FK>-2Z@3A09?+^#EwR7HG!!B8UTP%M5J+^!bAwC zGw-8$W?vd_SW5If1WFAlwejJZz=Flhu?%2K`7)ly>v21(gEhbh;yOXYz>&;D6vsZ- z%G7jkOolgZdknpW0eA|J<~Aw&Yz@E`iKIu_Yw@KF)_FK4Q^L2%r&?ar7Lec_^wq&v z$jDUhTAOVSkJ7_Vn7I(B^P4gj7k}A0v?*Jk(ovmpuh)EpQ&O>MPP^zvXilA0M054& z@gU8|IC@PLuoXh5XZTA_pNh5Q7oM}~KYNA?lL}e5As@n41U*Ki_CSS$1;LpJgom%s zNiOA+Eb#5(stw%k96dVXX;55i$bOH}ljcmK)`_o0^@omM@LbwqJFJ)srzOPk%$dyQ za2MS_wUI0`7WjE<%nK357caqjyo|tpFhlt4qC82+5h&IFQFrz!X3r-~^XB(^0jw|9}G}I;-J!=Vj zJqEkBF|Y1JFznYMh`O^J@_r5@%R=Iy=t;v?HqDgVn~;wzJ0O3s(;4oAGMh zztEo;!|q*-ja#eL8G$qf1Rbtb7MbNQR|`s#Aq1r<*FhtD!>G}mHO_(bmcOjA*465Tl3ZL1<01_5IS)wR)nuQ<$%i^iDATzYrJ>9OyUM8TW(UB-u z?5`l!>H>h{Sj{LW+zD+N<8KCLYtgdhnF0-2;F?92XbG?8ULNwR!Dkpsp0OHteloGm z=6%2-I%!6oDVZ3g@6As@p+q@@yM=D(;qy_cBB@#QM20e`#}yXwVMgv?!ROMJ$6bR> z9V+oJELlepgL?U!H!~cctUf0&qFhHJZ%P0;Z0qskCvxmtZ^Wx_F0L>Zeoq!ZOB5&NuCD8s&p+ouk*dav|C-G8zq0`>m>E zQ6PG3U#f(jtoA^pB)|^_P)rC5@D#ZIGO87TnZZ>Ka7hLbUOR@Po44E!K#*m~IJ)Y+ zOxP923V}=oJa4H#NL4?7ADDG6X_!)~UiADCYKbTm0p*njZV%Mo&*TP(gwcvY!9*O4{sWSi&A$A`5#I29xqJQ6^D-#(tZRa=p+!n! z{)#4nF|z)AjSV^k2BlILn{5e+R-wDLm=YuL(?{eK4|tb44&b2GN9&PZGd;yiU%soUJpEO=nmJ=7)0-tTH6;_3ja!or z{S#Y9&V8SayCcf%Dx3#^-*!u^s-EpeCT%CGJ*45^HSB}XYy+{e1&s$M^a0pi|EPwl zqmUKQB))yx>{5H&G=(=-Sn}K%kIY5A#%fB3M>W}0Q)LW0Q$&{ZN;^;vg-Fp?(OcyI z0ark%zZSj%6cTVa@Hq|~zySdcoWqCt7@rLPBmI*V8Il5N7_ua>lW55di$@ca3GNh< zZc}9R$v$dRm5szKF2&`C)f|xAT}H8(lV)vDVEZkqoz|L z(ivRGV%%7EcI-?*#IPB&C9#{u%_mL$_(zdS^ZrE>oh;q(vW|m)eeak2h>4ccGUPI| zs`!k#$tt}3%$%8kOxA{DjqXitm^8zP+hPgAYTmiNa?Iq(Q)65kk9WZ5CQW#3sqnhyu-025`t}*CP zyYZVk9kK(FYaX(yRjse6E)$F2vfY2}GAznjX!qRz)DRZlx-GCAQ^qr`8D6@sl?DEI z%BN24x8ice67z*w6}!~$F(Ze7OJd=@U=TGz#iC7d0tCxYX}|@c@;XZ%1VUzD_FMUqWC5Rg4HL(5{lz# z@cOk?8RN&lFP~)a%273(-baQWyS6$Rc1s-RiS_8NTOG=&wwviFt6}1CFvU4Cq|n1# z=4DPEnUj{v()#3a+^mT4 zeZmcLn7d}Yz(vt7LhMrmmxFHS?3hTTfn++U4 zBf*9TF%4=%hto~p#TRQV;d`IO9EK1L3m z{J<0+B}r!*FCKnw051q(4=T&yq084fLbX5#al*=aj15sPO*1M%|Xvor8?;swt$avlw^{#mX1Yq6M2*6@Dt# z=h51|W}clgxU?92u_KeiMArOK;F#?>waDM<9;u#`C|!FH+`f-84_z)*aRi-O>gQ_y zFRYjXEP`*I%?QtmdfKpQpN^{n&N~*|ZDGUp5@0m7cx|6sYB|&N?=*%1X<*4N?b0FX zRCNNw^oI6y^uQouha~he?O)V~8KLB7y9$N?A$JWgP9SC}XoOi;O}U%Y!l_o@29i&Q z6}XwOip+{^hxAu?-`~P}&5-u~GsX<_U4=^eJsOePqX!bUNjFCKUf+;s8;#ICyunE; za9e{d8fwPBf8G0|Lp0D9vFoSP6QDqkJd?ln2J{Ns2>SgfYF6!Sfs4n8kjjQ?-e?&# zJ#1P}N|Pn)nt>q+Pn`gOsO9*T?2!HPAgJqvj2S}|g2?Mosc&m@l{A)o-`Y)lHeoS0 ziZrArO(K^cS?lt$kf*)rYm0ToAq+or=z7axIwvDIY@ja9#I2hT(i^#k<)NgH?!e^J zkgMb8HMi%Io`W8souPy(2hQ7Co5r|FkA!YT+5aUmvzBY*eiK@A5qJYeJ8@acW{&R~ zmp|>%!EOiR9-|?S1_u)uFASLNQ{ig!y5IL2&+1|L%|XwUP(k3hJE-0v5$F44VP!(aAVECl4(O-aMO1M@Q<0kGD&`YjPFN+YRcak zJ*+6+{b6PL&nUI!*Mqjena*M_G32<74x5IN3YdLm za9tIT;Bi#BbCqFTN4=p!Vn<}y3=Gs^?H30>lwvcXNM6@xJEbJKsj0o?EMx>I9ilif z%IFykN<2*nHPk>L+Z}Prmpl22a$=17I%AUkA0BQHlE}t+*f+VekYDNBe#rU+d4lHv zkhhcV?i;v*DHGVxJv(vy0R#)`@v0|PXPN-6MS~!?tgMaT1+gTUu!U_yV}tL#FArw0 z_3aPVw5s|(=x}aIRjC$rD3!#E%^20u0bqV5Y7Nxl&H1xby~HvdI_a@?SebKtifvcP zerl5SjqZrJgFreo#tiJxp153Hr~~3V=FFImkIcXGJFM;xIy~_ayx_>jKJ`~Na|Uw| z2o(dd6ZSC|!oAib1hIi$k8a_5+F-)TcUUk66^=AgIZkQ1H9rSg?aASYGkbP)vNo?L z2L=75+t{2))Zj)Vy(l4cgGk7XVY`#x1^jq~StjN>pVZ~hGK(*B@Bu&b1EC2CtDAo= z-YV4~%_25?IHq-4h`aUpswqeOiG#hXbniaaxjDDjk-;betlThW1v3(E-n?Q3n79=N zfL95tbmERnp?3Rf&CN%D9F#{iauErzym}VC&agD_(1~g!i!#G+F@6PGt8~NWI;$m< zz2PxK$nF<@Rp}hq*1}+@@4uwTk|0D^NJY^TFci^xn!}_(qbZy9priKar5njuBt!rJ zy8+Dz2z|m(NITDC8}Z%a`P7_`yk$b7JYS@2tRP(1PY#pAdqa7{pHL9wT;2Jv9)Z!} z!2Ii@T7rN-!PGiM^u@2x{Z|jh! ziV9DJ{H~$9>cOQHc;AURg_rym0sjTF9UibtXVcUgButGt)K267*GoRtm@!YZm9>Kv z5GqRQGL}vR)(h(=<&2U(5HSTf9ri?sfeydHjs)>w7e7ZNy_CynV3bUv8AJep%>gw2 z2zF2@zj+AS^`J{ipyEFmkAlC25cNU-L&gIa000mN007`S000000002WmZD!~z9bmK zgt%9jm_FZ0XteP+xEQ*`GK9lHI_(U>Z=ith9S4+_sBIWC42Xbxg! zWw|8$sIBFgZlSb}dV?i8XUvdW#buw1Xzr~F8ll>5HuMyjSTnqSZnE!$_Bq%Xd zz2Q`-gCeAL-V}sBm+g(Et)Uc`!($t5=~6h2B;q7_-%^ZCR=CYq`-x70 z*^}|ojXCs*U{B_ap#PS+>_+mxM2mjyccCV!8d85?-to<+wft*G(Z5|}o(ar#2sNgY zyvAT&HQ1x*MPLL<10xRlmT$$Rfl57W0k+4Uk%RdSW$(<8U^2&)!h(f=r=9i%>|G*n z9qqr5m7l${b9AKJLbq|J>oI2fbJgp9y$ zM`A~qC1{Ib{u@mUfd>F1!^4kf1{fV0OwNI7)rI9g__EmF`(SH@Gm3tdte}8N*5S#g z7^{QP=Mlic&z53D@xforIEkI8B8!W@n9UDsO4GVw#IzSl<45%(U5Bt&p5?^Yw}}wA zDRZ{!QF=@X8%zn&=QQis(-Hb@<+E;hnZcueXCo5yN zRq8)V-X@c~R$(^lDmQ*k)P#Mh08zpI44TO6W|Tjc@bL}1s*T~i?bS$oK%BEdxb^}> zKcfsk;4xIduS>~>*3Ff~FszPklu|#CND_)o6*>E&Hfb4=sVcH$WxJicKH*o)1MJoA z(jt9PMJ$(`Hk_(=Nc9jg$Trft>{j-4EJ)_ik97D3kOnI8VI4y4ikSdn7$Ud7Rf>ri ztfJR|N44KTD~3u+3H{zlCKhoNsbZe+--p|Yo(weMFeRP*cUBV%SXrbkLo&Lw*w_V+ zM|6 zpxuWN%iqurQM1Qf-7lR^1gpyG8ffY2b$#A~ub8($t7*WcW}+&|mvA@xLDjKZXt^sl zO?hR!6G>z4*lc3{dQoDXbqpkOUaOtQ47{UI~S3-4QW(eujpBg7*qqdK~=t@fAOht7nA_B697m-833H1 z3IG6L0NQv4DgYNK04UZp000mW0ssI2G$UX&004b(yW91;rQ>zH7N^zHVfxsKy_0eZ9T+YPU47EM+j3*hUeEW{QO|0|Wt~K@eJc z<*_y(Bmlr4YE=-3AQpcNm;eC)8JV!60{~F~rzVZE*(Jp!5=GBQSn){`H0s3KPZL{8 z0e9UTqmWI#_d;%M+wN{w2Hb4-J6$%m)V?_!Ms00+a!T9UDSmli*A}gOe6%XAR=!Tb z9YsMoGP%P6D3D0p9I|PWKsW#ZW(3S=3;^d1`JQg?+wNVvnJu=q5M8&L?q0jw?RVF% zEn5`Ux9@S(Q8JK#Ig&^SVkt2)QGf^t5{*I;0VId{5#a~;AL2of=?8#4 zeSelr1Oq$&B?}V;j}danNe@Vc0rk&7EQR`n6l9JI`ox8fISPg_dP<~#DoSBwVyQWw zh9;{^LWh(WDNSsU|bTF+8NNvq5}^elRTwTX`PMHVTdHk zdz|d+X;g&Fb~GtDRn;miNLgRlmAE*5`urz(`$C&vChH}UjgkvtktxWPkI= zXa4!G@gkR|7iXK!iEfXXm7x%x)nd!-_4jkvnMQo(1m1hPlqyURcBTQbrXb$Rm*E_RSbHve$x8Hc1dK64AxdG z5+~@w#BdUzMuC+buoF7^+v&dqk+@oEGGFS{_ya?KpY(kCH6`#W$HYBGPE@+sDsDO& zB?vM#Kun^1bak(%vxVo39TCzl(=&NPq_7#!)HKG<>e!b$TTf1qOPY)kyIQtkiC3Il zsMHhES@H)uryGnO;OapY<8F0hW2n%GwVu;Xk}Qg28ppLZQj8BOQ(E0d$r zR&*WvCS`{);FiUY-3NtnY8%hTGdc98DXLD(F}*CC^wy#6ElB~#s07RuolH^bICR7SrQk_<$^js*X;hw0m z&3toUHC)Kg+6y+Q>5r@v6LK2Oib}F3nDsfYgNSlhP7ECJRclRMnORl>oAe z)tAnxxuMiycRCV~WHiI7P(Cfj{SmYk7sDeC=eDY{|H;?Bg(N5|?t<+cW6u}Hd1t!00z zZ|oQ=aF)3g#&;za=IJjT{B%vzg4dqN#+TyhtvO=i4VAwy&y}2s8{(yCk`}?ROMW0P z@cH?ZBhfd~)Fc~zrBAA#8(Yl%wXSTq?IWVfU9OQ1ZUHoHGSY73+>#y;pPYj)XnPJD zjrWQ)Kj5|zCh!!hAprcSe>OY;qG`}AI@y{)X%&#I7=jIPCuW3zV6|g>{}cLXgLI;$ z_HR0YHCNNbW*tlPiPll*RBAM41gsyZTPPqq;3P}^08SfWAq*Afoea(wGBem=@P`S^ z&brVMB2*KI_X7)yZ)DH*ogzdk;Ie>*o209q)!y+!@ zl5Z%1LycpA9zRVL9YL)tb|(ZI_Op>J(o6Yg^)3b8_5C}%tKAR&0pdf-VqO)XcO>oX zsetukIqivRnSoJMvKjUV1T3wsW62jI9og_$-zWqeF0;l*YT;JT02sTRer3}#TzSWI zK|#aBrxH3RVgQf8;h(^_L}fRM=VlpN$HihLUf-}XIOp>#?sLw7$vm*Nq~9O&0id1g4gLCHu{J-cz4vZxjxXaxs2Uu`j6TTT#(ypN;VDmG7RAq~vT9 zdk*4?>sakGUR}Y~tmHFDhQ(h*s{$L}j?g=2nk0=PbYUC#1wZlee-q3qYwOBBC~=qs zRhk~N_&7w7u#<$gIwK;twpvAh`|+Qg^0Wu9hTTb&Y>*D8^yml^FcYH1yDc&JzGWF@E?1g_>i?As1M(v}E{BwK)NZu^v&GP}axG4~>mgZ|#qXOY!DLf>o}y%TI*mvj zs;;gRlp(SYGllv|ZTNC_vr!2*Msvoy zomLUsPRh0B*t?HF)3oEs!@}L@a=Hf0($2?Qml?oi&X(y!?c^m2#5@lkjGLKP8vl>+ ziGyA=vs>Ed`{MhqXWR5$(2`k@t(>Zy@`6&1aP4~6kY`DS?Wk`etBTCco!%!+(@L_2 z;dA$~u$y)vvlrgmycfH2n-+p*9Pb$o@oK6-FI^rxt*)(ySZ|Tk3YY3k6Ipw*tzicf z1NJsxDr_~`{_j`13boWQCqf|wum>_|OT&+#=haCj?hX-Jb>n+w;+RSyG$+LqV6lXc zW77o3+rMCNeiFIOvDcK>LTB$~+^I4L8`9>-{O}rpn%L{%XZZ30y8uze6D)jEH;}8) zNWS?ZaR3KU0WG@Xbl4NzAAL{6V~0b6kV84-Lk^hl$Xd(z=N5>CFqc8Lt@;61X20zA z24)yh<=Z!9z_bjuZ&9Txm+IA*`kw*=K2UvtxBWL>*wvAE-^>B$#}Q(}y!;xJ6an>zjQ9w6Kc?kx1%acIvUYc%Hi`g-Aw_Zh@$*oG#Si#nM9Z!5 z)u`(o1`{|D)DL-?02R?htoVb!op^hB`9bWH0F48Rn)0xp6#>LYFx9AlaayNX`2yTr zCd+3^MZo#-<97o14=dA(D%e~TInzfFZz4RAgc{Y$6UU3RO;{|nA_DjiE?LQjP_)34 zI!)gs*N=Q8ak?8his_vWgBuMUD%pU=Rh~^PoSi?}?(%z%3Fw`gNZ0p&sw$o5ojzhF zl-q`;YlvyAtK>hUfs`wXMzm>luSyVC5=nJkQuYy9&w~*IJIz_|D1v!%3NtVAy1Ol=q6ZJGg0@pup$^2y>3pxN!&%HM!S@Av^%pyuXkW)HvvT4vRzFm2T4iPT{07haIG2e)}F`r z^!q&hKXsUw)GLc)LS8|!zRn$o2(yv1n65m3v|O~zemXsWBR3N~Ao=r+3;+*GO!a4) z-n-mx$Zpl~Yhj15K1@d=RlRN(6i5^exSxq@zVdWTr1ZRUVI+BHBQ@73 zwl*MNp~vX3X(g1bTw=0!3@#{X2A;I#tueri0V3m?=$@LJVLykmZ?*<~ z5^!i8Hig}EakkB{3E6;B93F9EA~v5!-*(wkKM+3PLiJ6yJU`c=YvF9;{pP||W~5A} zX4j&d@O;YmJ2&5^UP5(omeC%%fw#_y=G5*K=ZF&B&w1ftdr z-Eg1%j{uvT`4M5;v-XPP2fagdagJ`0PB91Jo*}~;SiAB!#C`z9J24;b%ZJ>2ju(mQ zS$Kyi1@Zcan&B^QWLGIBGJk){k!oxgh>2AWmHR*=P!a3Ss0lFdjy^ljI?ZVB7e>E1 zQCXh#c9V?g2V~H$-W?eKfLbcocnWQL(2g}A^l5_YkaFQUZP4j#=p;*#xxF7qi}Yc3 z3kHet;94zG7Aj^<;v-RK88Ntcw?Bl20*-?qwjnxpypnTU zZw<-<*Rv^%GzkQ%p8MiSN?7x#9mD?7U%QWV>&!*?AQ9J(=@*SLkKG{=2n`tF-ClBK zgBsGXoELbF4$8wUfGgo7SfF0|qsZ}-7d&4Ws~?f%Tub>-qz})}K;x#O(oW6whaU~K^UOE@Q#fs;?xy=WHR2*%j zW?p8kN*7Ai>|(0hd)5wi%N4#UrUPrOmbb2Wtyv%MYc;%41?1CmzHj4%hLFjKW231V zT}Vucl82SYEhetcW319nkYGDyjM;kTrf-=wU-x0mlQUxio-rAWMvRz#9#j2{>hMhQ zV)b`S+cQ^-XM!~jwCHRQ-J}gk#;b7Ce$S-tEMvvnRq3FZ?OwbaFF%t)I^6-MJb#Mu z-Gw`reLcy9pH26Y^-e7WrL%x+>ADH1rFwAZ73c>ltiNmacUCay7>M+ShiD{ikwSqA z*x6FjQWX;O2v=T+_Cf{|8tH~lvu#o_Sp%Ih8-2idj8x0kW2X?>9@1}*lbnks9()m+ zXQ2ft8sAb~luEe9O9*Am_#kT?0{SA63uH!)GWI0{=AsMXPv+Q0XT&}l0B&TOjkE@f z>3teI+f1FTF6mMsCp)fa#9tHP)9KBb(Ef} zg`!k3>U5)+nNmDzo83I>(BJl>fbH^8C6<2pq6R{V4uz9=DXf8|Iz_^Yn7>NhH9Ne~2#g!wX(}&&ShDMNSzj+})qfoNb2E8G`#eHKbXMdjl4;!sh&F!e`Kf{{Jyy-FiT6bTr4qb^Xb zLBZXksuZ;D2D?;~Tu_Q=YzaZpl68=5T1C5=aiGuI6=hM-fn4*FXh$q)poU>w?%u0I zS+R#`reTdEZneqmlUDLMlhEg7?*J#FN;@7R+IgR4)DWR-#~eTSc|=%~ZY@X9cS(*D zj+HrpUGLxsy(_Ffc~8_3*#%W#%ZZX}~lBb`HJ^yn;DC$XOq-8k6Y#<4sXHr1xv=5J)$A~^-?%3iH{Ba+T`4bts z!`#NiYg#h#x$m-Ytoeta{~=G$xBTSm<<#Nxi`?KqPjcKB7Y~#VftkN~FyR!~oSc`! z@WNhP87EWxuHT;FulUV*A@luX|7FV!`S6c732SfcH@x>RWVw8k7{~Q{r~PE>xN>3t zi-xcLgMReh?;QQ(8J9fzCtv#mv;Oh&%YI{|94;}*({DpI_ z!InWtqTkOwinlQ4kKB9bWBlg#r+#qbW_*wXFy`N!dAgzCXFp5Yl>4VY*)aci-0IIf zN*#U|3;jCw_C8-nxC(!i+vvCyKjhl<_!|qqzJmO44@Au8-)lS=STJV1_ES>T6Pf3O za^~;27huAv*8LR|d6jX%XCHxz4E_zQ|MJ4$U$F3t0DgmC{p{aE?=|xfK2Y-S|2XYe z+3$f*>oL4<{%w|L^TVJgFy2mF;}uPw`_G=&0}eX(UJvu1)_wi~^ZF=pMP}I)A6e+h zCGG?>bUE9fa%g{uFPvkT!h9&Zlt4ab#F=5x%PcW+1hI_d#l#A+S%ml*2Rn4Q*C66i<@s`M-~w; zUeb;g6Fztn4`7A>4DbdNK!AQB0HFW?AreHID*)>~d;Ryi>-~P#EZfVLle^YtyRlbF zH?o^G6Ag0>5D~;P_#l2n{4n*=0*D9ukL2N$a0edlqkS3QL#1ts&G??TnpxuPH8dX9 zcrZ8~drDem0s?3sY-qcy7bNzI^bQ=c&hECn%?|NOT6L<4w{>vL-S%hmUAElq1-Fds z6>vryb=&yjX+QYrt7?HkmMm?{!>%`CJ|k9DcAPJ`!tSv6I&MVn0H>@|D4Uv#JY z8*`8KF>z)G&fphm_nKT+2@kkR(=|dX?lqu%M22s$(9Vs1RmhL$pyu@XKp*_Ujicm+ z-nh~uopLuZ@(g~b1RE1J8ybk48hJMSYzRLlx4iNY_%#r0NZ7y55H~gQZ1~s^{YW># z@(}nn5Nu4?2#XnRYvkDQupv8=>ydWMH)Nz8&DBXnDJLVSoF`Cd5vLFojG(`NAt*sj zixP6iIEA2y1cf0e3PDi_z>_SJ@5-4QaaKv#$Q>f~`A32gG)KroPSS{$XpBxFC?dp` ze~eBcQ5^v?qeR0|QGObNnjPJIvmataG3&IP(v6fXE8jy#mPAbw5|PA3fk!J5QJU!_ zWU2FH3XS3vf+7$Ug`h(OO%x&krZeHSye2+Pk9nfm5-~Dcl_e`98M#PS*^@mIKO&6C zITA3U)|oT&60`Z_@e%!PN$xhT9FdjJY!QrXlcAa0Gdyyiwl3Z+JIM8?BAmhVJ~rQx1Ux z;NjKAwUDl4rQkWwJgpRdKXPdhxrsG9uJvM=>b;v#Hj9&{+aBPNi+1)+-!7tTc{xTt zQ~z(W>r@qQL9{ir9^LVbfIEf0#-Y8%E_s3%IpPiug|%)s7xJ%{zCricCl7hZ8O%Sw zJHIiT@yR}T(wVCSHtIdw#9qxD#yqa)v54(1qQ>|IS6s1p(K~8n_-*PWRR@+S*ryOP{mGNy#tyW;l-o$J8stskU@W4Nu->B|dqqi@-JG=2~UAxU+ zX!>(6gI*iog6U=pJGs~Kd-|T0#Icv~{rj^jyMFZ<@BWzDn&O%}>Dk)}wcz3QuWr$& z@{5MF1>br^0`nSvhm6A0qrf4CQ+xS;`45K39+7%7|2EMP4hydxhoK%)NP^QTq4%9n z28;gc*~H#VCoyQ_51-h-am9jwtQ_l@Yyi>eI-liLIbD2shD2xt+OhdwAiLza3UMY0 z*Tilf9y7Mp!I9hS^zq0ScBP3{jnRs?i0-uc>k#C@r5B%f6FHC(!Htn$?@2`JKR}+l zZH>mUjkmRz%6t&LoE$THSupAi-Y=o#8hf}^kqM#k)f(&STMm95ssznhPseCI~sma(`Ob_4qeJD8FLc%?Th)~&F63%Zyr z(j-DI8|8jn>XkkXBUBUcI&O>k(lJOM^njOkUje_+JFPUGerC!JwXF}8O|ISQ#B&mz z$GQyLI`p{^s@HWI{XDNGw4ScaJ5f6*i{3Qq9nf&kp~@1M+k>tghk8(e6qh2bD&~L| z^qsHVqzNxhsV`^*sK{CYQZnqsWdn24IvfUdK^LIHd8c&LgRp3PN9yQ|kPq{@oG#PP zeVJT4gQJI)>N*vC+vb2yV@_Ij8xo6pTJty@xd=T;Bp;OSN`_A}hwVh7q25q$9LQwU zW?G*6C5tcNw9-6ulZj|N7I#P(p-=)`a)RaN(xED#A!&`(jsSOOFht^fC5;5}?Npsj z=PU23F8YLqvml=4Zf z^H2T`oNY6Tm{QLs`9WjnK>MlQ^@hxtlB;*3=LDswuPR_-u_By}*PS~9I|wfaSN?6+ zEPVH~X$$A^1O6#JL}zpOBklhTOX4s?I}_^NF$eqebdu40QJV~$@WG3=RX&U#evmsm zeo#NOF00dESloaf4MjppeWFl{nSt_C;wiJ8>lA}vrcq~h-f9{m;_Y{nq>V>`n67y{ z(;Zf$Cv<7hbtm&3VbjE6-)ZrcIUX!ubb2Hk8ozh28f4S}y;;m2#pstnc2IiK>KscM zrKJ9vOlykS(C6beOPq~shok+G;-zP+X36W;-QA8pN?#$ad|ytE-;9YTc?`%4KOPUD;yn z-GN{R>!JabKV{P2(4(fqgO@W)u&KD_=tGwE@dLN-n-JVb)c_<#l0s~j=pyRg6Er$- zLqxf~Ysq8>wX<|Hxsl@`o*aNcnH?Ha$xdjvoH_?sGS^?aq%B z`W_@$oyav-T|rs`QQ`Jsv(-wNWQ9Sc_J^37oi%?NC?-f0&nrl;Q1?e^^DbNXOp0hdEs9?45`8l-X0%C{5Zs zR~RQI?kvPrxjs@${Im;g>7is{19b*U8^YlN=8Gr_B9GSe$}ePshf`!b zzR2vGtM;~KG2vm4I{<`*pqKD-;oaU}*L;ep1$*~PwhK^E+BvMV*d@-v?pRZVGDu`) zA)W`DVj%Ggh3?!>Wz8r+wYevrY86_zZ&%Y-?`$=2M}}g(%qRBI?ryAZu^+1IUM=S{ zTW-&gdb3o7V+7-dgj}L~?j~9tF#B zoQ7XW5ceX-kdFPEYK&7UK{ZO<G?pQnp}U35=tM>5{AlucddT?fAp$^GACf)h0#wuT6DwPjxU2%4}E| zYFbcfiv46?9cTRvt8L%)&WXfRI@zU=vSrUZ5d}l|B*F-o7$TgIN$rwbY3)gDX>6%( zId6i>hy{snj8+q2VvgeD#XrbodxYE&JxrF^b*C|ASCp++dx-gLBNr}8K`tZAr^DAT z?Dx&1iD`0A>naSa>X>!ewfN@I%C;Wx>@+$n2Z7d7Qia{jDtJf+L4nM3+Yxp?@PljdGrKmg>ebBZ208BGAPsx02-;$J)2 z#Xe(R0Qyl?{VM3`0JX<5SQI>8w1OtNW0?ew*txHC{qjbIG&iu-WLfn##0hT9s*MnZ;0=P}V@8y658@#^ zm$y2kkU}d?^x%`DP#lUX7tkE7_?SVRau~A*Y9H+VfR>?qj>&N3b1N{I?W1j9*oJco z??C3UCw2fU;VQLFrlwkh(9;nR^JUfn8#RDV2CgtG4B*%MtlMIs3}cRhv%otBurZ-j z3m;i{nFB9mxtdUccP!SnT~HX>0m$`TA%N+QEP#et>x~~s#uoW>7Q$E70)+8IO;95> zRjh}*wtQdEiO2YbxJ{rRIu?uZbD+=s1bU~dBwb(qpbm%O#bpy*oU&e7V3xRkMeGHy zm88);b3eFqY(L{MqN=p?>tTbl=8uA7t^=!xigp7LH#s?@H@6L_G!oa(a;MTo@2)pi zB9r_A?cu7&@YgNU_v{|MhN}lk)r$sAVMO_(F|?Ke^-Qox$SU2@#B&6lqI1!`09z8= ze=-9JdqQCC3)?3ym-W(WCpjMcxB)^Iu1^o%5)gjE@Rk)`o>@{yHwyh2D*&62yC!M= zWf39ZS3hgMKLamW=(I&=@jV zseC>1tQlN&#R1i-u@BIjqpFZPIcK?s)&na@N*HI}a)N`nEt6qLl*zE#{duV)28Tre z0Jrgbul52z#l;14q%B!^k5YnBs=P)8fo1ZDpbc{>^&7W~5NC|3g}4C5UULPip&<0j z$lA{lrvXybB6Y8*s#cL z!XKwPEFaV2J@9sr2r(pTJqY8-Euuj}ifJ?;!En&3{$QEWN_*Cn8KF7y0LH6#SQW5z z>Ca|Sg%PxDhJj+AQph>rLyaci-!tw1?7NZ6<^2;NkD7`rQK-oP32wXiNh@y4<_73F zkFf@oJ|GEuMfG}&NKQ=t-%rfUGi`Pc5@!c5LvU?U#Y z8JL>w%Yx}q9(X+QZInZ|uoM)p3Rr-n2B=Xv6>~v{3|L{58O;Z^tz*C4@(IgCg{^_Q zeb_9Q!_(0EHZa)W11+P;Tab@lxnQ;i)mhG%q}QYQ4Cc|42JAkzc7uc-q?0vR_}F7F zr^#C)n{79+?!fMH7x-|1UP&%B-|qFe!k^ZBQ`(aD13|;|t>9rz&WPJEU?H$y95YY5 z^f{lg-35Y2AcCL=QS0l6^Oy70`YD6II{7E75Nbz%Y_@^gHpce;Q8#AC6UWRqS z^Bp=&jkOAfAbz+q&yD|{rQ_NLJ70u2YVr*91C84T;BE)r^Vmy|lP(5$8UAjeUe67D zzOu%H1CJTW4(XZmPP7#WUke6VZ{G4C!DG;NG2CzBKyT{uMwJrP(ETddR7@yyMo$|x z`$_}&mLMi;pHMT(>l{)}{Xo}9sA2_{gZ=tZ6NoTnK1%7w2C_4jn9Yk-@D4I#0B9BD zbqXq~gJq*_z%tuT4CM378#zW0A-86k9!TbnKt8Pz^=1D{B%pv;_8Hlm5qU`sH*x$J z{cQ>P{mM2W(l?THeQI|g04`*`6}%EBaPd*2cl01mB`Q-JsG>Jm8JQNA8|P*q&7WdB z*9eX8(nmcMWN_~ynKpYvnNi|tP=5wgV|tN_lwiT8^%yCbmEoIAWy7-t#|&+?3|?96 z)rG-g11#4uvkoJM=PqMA^$2Ffdp_s}5E%)xrK%r*j~dy%5*yOBG$#b9TP5)IXb^w% zd4Z}t03KExS@uK83W;ZmNj2kEEpUE}3!u{8IjXR4tFZ1qrl=HuPnGF6+%ECsbOh$@ zFS{X_e3`Fc4%}ZdhDcbdJ=)}OXXe~|HK)|Y(LIu@^98Rwjq zEO&ww2X`QqG>k;k&u3J)q`q%4PYLG;8G@dkywL_Egjyn%EWuGjQtGglX3ouX38{u+ z<*FC>=RzLkm44PPJnHo6fxk%lTucuE`TsOyZ^-+B`=9y1pn)gF7v&Vqz@Hh3`=bbE z06`2n~(ndGFHE-`TDsJm&c%*4wdHl%Cv_~m$IrCAxhA) zVkxpADbeLZP?0v9q;+hF3bnaVC?FdmVl5(;EgO__ZZ2XoX<`$qd}fb{8_7$bHMUqNsY+)BDW8TYRLzA_6~+m5HlYeq zW+$3Zuo6T;RMrggd!s>+?-J;D?h9Ch-qKg z;i^(o#GR(D>&Bp3R4B?nt!}BPSE>FlGd5^Fu1#NdsQFu9B+CYK?^G)C_eUB44`nNLh+2AIGkpV?(RF`Yp%u`@UnHu1!N zhLkekBqjbAjw2Yz5}24+DI*Hf?+9-nQDB&98_H6`Z^>=oiL(TrCiHeq=8?OH|1uC~ z^%x`5do3pt1k%{jb~`~yJ5lSo1iiG#+SVrd(jaWRo9jyi!L+}&pH7gc0q}Mcq?+R! zZv=Uo;9F29h_udIzbDAF)!e@)2sGNbp-+%$zqx=-5UM@6^Gy(`Y0MQ}f{~gC-NGj% zwUD}qPl0M6c}a;SYUJ(^O@!dd@I0ZLa73X$ zY4C(&DjcD?&|@C=`=KNtl#MqNF4e#U)WFCW(?UDU?J> zNhFF&qESo|C1O%2iIb8^6qH1wm?TQYq)`$kC6XvSp_{lw!J+x7FXD;b#1m6Q=ab&& z6TgHfCK8Pg4uww%$G?9s{3|~Lru*1^5}OeB-Vn%y1~QUxH2`-9002|tSVLnP5+DWx zP4+|@8uV`1J&>N8e`9wxu-MRy?(!CJ--aDz$GF=~0`8AU+E*(XpV1#mY*w+*Nb$B- zkv=R+@moB3EG%pKY1gmTlFr+2TfdE#uUDh#l`12%swy)XA~?9Bqm`yHsJK>KhN`ND zFs$<%<9-|n2{=X=bZhg?ki!}U1V6YTtQMyU(WDeL6g5&^X=%Z7uBRPPRo`86-%047 zDUycoRo_7DliD=kuBv0G?_OH+&ik93l~WlA&wKCL#c}8J-Fm~!c?tZ)=-HUSpIK*( z009&g0RR9I4Mzb%lw*j(!QL3DjQOf6tGr38*%$8b-$C+G*9DU1&ind7r#V1tuIsFN zBkl7EUH%d?)qHbu*@yc7zed%``ERx7;KMmS21SX(*O1|^U98zy(#r?cNXe5S{srFe z-UILhvR+$=yb=MVJsU_O8?@8BfInXNxYzjwuk+^1mhf)EX4h(HlI5gNUI?S8@8Gw(3WE>eiT8VJ=)DL$|0o zijEGvk*u&AHUf9%j5r0JxNQVh&<`IG5ksd_$dQw~_Q95qSdG&~=W${iKjBxbSg=>3 z^{kKGdj!r)S8@6vy_>E-rfVdwh^L=>dt%gMg^@8@QDBU2tiU&@?on4c)atnf9jPDO z-Ps?buLj#vVL&t$qNdVQ)tmSwU%sCOGuaUT`Y31E6?lpBVl&$5h|@A?7g9xxrBt4 z)P;rS)G(4Pdx75s*5>TFbMjC-EoKzwpIsoQBObRz(w}NS5}#^1QjBVDU6;D1=JT(A z!c#;5RU?uDRr`^hRV7K!s)!_K)ivV;TH22atu09sRE$B1G4OW`9e(XGfGs=Ns(5+y`@u4Ns6kz^;5U)rYS6+-SuaM zCG+cn8I~R2*S+IAi&Z;)txUXF9v+c7$1pYatyiEoYql>|=<*A~Xa6sAoly3lTi=>) z`vvXf?Xl0MiS`P%kNIl=dmn}F zKyhu39+F5=d8lb2|G{nZA?k9r4$VwyaI_mRhbWl2(utSM!=bNQ>Gw?yor0`$=8i}9 zWNDCt80oCCTG_9Ld(ZTs=SdOVyKFz@=P{1Y$vchDg%9w5s#?gzK`|_RSXnw7De5KX zLSyX|Eb5eeRPQ6(N@|uY;sg{=>hZq|b{Cg(*cZz&e<74q(X)psI=C3H4gFj*_72cK zIB7|c0){I8`f?Fn;~#i-g||)1ao&*igeU%|7Y=PHzkf!_mUaY54LANg5w>Yf-*}Jj9W{}U-4y_psf4ipJ{s(}3 zziTSQS0Xy#eoounOqV9W%T!X(^IU`L3lk(oB>O{OE;=T}C^I1&68^(yV?}WSAr&zq zSsB{GM^R7<1PsLFiMb@82mAx$R7+L$A0bPUZZ2eS7{aki8F}iBvgkq`)|X*RlTx`} z?nYKAt;fs3Y#gj+DKJUnm5)r8C0d!Boyh?@+q)Ua;b+NZDPa~6zhcLT+@vwTjs#m0 zuo>3}GB_?@lA#(Wp~MbSdRg0rOwmpn50wn50$R?J=9bhct#@$6GpRbQZ=BK`nbqo) zM4FVh03T$ICLi&^LGKb{B6i}R8CPTy5Fa5{7+$p>^h(72LEkHj^WuCcCI`R#yA zed&d7lLRN|wN(G6cA3&s*C04EFKcb)n=F~cn%Sc^bWzkfin!~phnx8RfEiTP%DOPx z{s#oOt}5rByn8WrfAckvPEu~;1J|PXGoU3g_$}{jw;ky5UI?W5)mT&sVZJ&SDpY$I zWUx~T4-keI_llDDm@l)u*-xqaJJc5GUBRo<1sb-_*F0)3aUY$;4_m+W$bi5oxQ14f z{yuJO6fFnfpBL3e)Z3txy5YAL2SdlNCx23#8@lV=klhQrgCtCK^6iq&yiGFX5gCk? zJi$U8oA&ueV5a4Hibx?Jp{Wc)@yX=My*( zL7_7NhVB~}!;y46N@yX6=YrUu?q0n2-ayE&8Ho^2BXfon%n2sU9aqf$oy;6~8J}>H zA=e6|(V|~0e$zg3m8eUa8xk-7JsYyzuqpOft-`Rs zH^+xTx^N`$Z(RqLP=&Cgt{C(VUdUC!mI((V)P4m!0wiLB9-ShsWtBKhe;Uo=S~*pirGTs*K95*3FV&@Z1ZZvE zs5;LRT(8aVhx$2Rw2m9u0ed~~K_>+K?D zQ->Y$as3~}ncAQf`Px+BhWYurUqwNYCk}Ae9}f!cSZ}aN419)jz}OD?14EuQj7E8X z%#CFCGLl{2KeqR z93I_m2RRq+EpkhL`5qeZZZFA@Dd>i!S9QL#ocuX<;Di515AeJnM5)m&{DwdT6}UGZ z?Uh#$Y6g>e%;_3}a`FG(76i>` zmP&lVdBNoMCUt}+xUcScH_sZfJF@aMJ)L>t4NOU#VH&1h(E9s5WOKHKC=ly-4$9jM zEE55DTxES{$aq3gb#=7Xg1ESn06x3_JrvU+xr;S91oUY&5OtS?NMJf*nj>gnH;|xK!p;vm&%_V^CrBt#gE)ST&-YNyWb6|sl#a@W0#~i; z>m$o(W>{vB=VoSS*c^DP8JSff`(OOoRt{y=K8i6ijAu^8kQOiFVY9A6YRG}3WZtmf zkfh?J<7%3aopW%u8OKyPCuxSr0oa(YMje=_9za>@!5@Kol$Wr2q)=Bq{%R!EunQm% ztoS>ixZ&obHjK|T+tb7Le3)`4dNMDRk&f~7`9jv>k+LQ<4;-g(@S%OL4_-Ptc@aJr zk`wpgV9(o5$pjM9{~2-P@y*dEad{cg54z|u5EJ3W&!*{eT{hXjfJ%vY@F;a0u z<@HFN*82RvNu61V2%s4i!^wbFKSOa-c}QPvs-( zb*|>|LLp>$ExD{S(NZG@#Cpwc;n>Whycyunvc`pAE{1-#>?b?RWqK22XyaN<5izLq zG3}x#N<8`Ivbh*zRrd}i%cXMRd}MQ~*Y|+#F6@H~+cQQ)+==?`zmk5$Th*v>#)!6daf6%pp=)r>m|T!9zXv%$ zALcUT6Mtq3n2oAw!Kk14-vkwTET!yNzq8HH5YQa2_Xi z6ArY?2h91VXJre5ABlpB7?R_uPC+ir!7GnbV#s+GP7EJgiPPA@5S(diaorAAD8cTF zo(+{hTmwJS?xrM^9vJ3Cjb7lKA2tJXefPF*(qK0H+>WP%5ZR?E0W`87l_1-d}X zD5lzwmnGk^*g}kFDKoSYTC`RLhX8ULYgRbqRFhv&BaU?N1mOv`CREcA&Ol-s3LLOM zHC|%Ag~wplRiIqM)G*!|=tLR$*5C{C!vov@H`};}Zp%9qGHhg$A0$Zngj}Sk zteKOn-C%ZcLK1SB+AGzQ|wl z(}r`j%?N8sv?Bl?>1bK7jJJ04HGUE{IkB<^jm!^`)U~VD9>-i1enVWHf=1p#&r( zmW0s>DifF>2x~^{;aMSkj}M&%D=XDMuESWZdpS~JRQpQx2qm6g0dBkhc+@^B0pv|_ zA4B|gY7X?aDh2$T*C?k~Ad>?3ZX{SCg<#yJtuvTSKL;8$`A7cht-N$XeNOMa8Ucv0 zrh&TsHQV*=PJxg2RW#lIXFh{(*HiUu9H!!&8X3A$mS}|ga|I3Kdt?+z(%LX`jzS!~lz3XM#v-%kdpx-a|XEtI#F%U`ccf zvTc)Df*4cU@J({p*ZhEm)`)|q1x@yPo?`3uKr};Qua`i!$&&kVx5UlOip)w^oEaQ> z!%%0aOxpsfQFv71R;G*s9C<0(+17TatOJbmV@@&gRIsiV48}%#=lF8BYliTqKl$J@j~wsTyyg=-C z%jEV3!BoWtTqx4?vMyIR2#~9;wT(D5-~$gCg3A?r^3X?$xE5tbNzGbB=&dmhH)cvO zh%rh4Jjn*eCN_$3n^#0^0dYCLV{dzC~ zLJRO}{N-*0x*=|8i+NN*e3?lRr9eQ#E zJ5{&Y+2F>)$J$A*c^}yUIO;G_z{M3|F6t>&WmF< z>e*q@&`PqvSrhE(m8s@FO5RNiH4=Um+Uu4-0N2@VsZl|!+dFxvD#Ew4c>R?IaO#)j z)M(w-=J7+y-}_yi#H*_ye~s4Cl5M%E&#i4osmC?6bB9`X$Q<7LqlT_72UQ%bNJ?4o zj!yVuk6+V>+#&NXlvuni4lgdZEu3(caof~1^%hy^f;Mjy-qNLuCXsjsANoH%MVb+s zZh5(!ie|UNAxx0j2?AR%M##dN;-J zr&q-Om)4Juy{qW;GA*batgd@?!W!q}OH?yUAY5WRkB^_

    %dT8#&n9#M4$?9@Y?VN*Gm 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. For example, if your KeyFile is +// located in the project directory, you would specify the AssemblyKeyFile +// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework +// documentation for more information on this. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/ChecksumImpl.cs b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/ChecksumImpl.cs new file mode 100644 index 000000000..b110dae6a --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/ChecksumImpl.cs @@ -0,0 +1,202 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Runtime.InteropServices; +using System.Text; + + +namespace DotZLib +{ + #region ChecksumGeneratorBase + ///

    + /// Implements the common functionality needed for all s + /// + /// + public abstract class ChecksumGeneratorBase : ChecksumGenerator + { + /// + /// The value of the current checksum + /// + protected uint _current; + + /// + /// Initializes a new instance of the checksum generator base - the current checksum is + /// set to zero + /// + public ChecksumGeneratorBase() + { + _current = 0; + } + + /// + /// Initializes a new instance of the checksum generator basewith a specified value + /// + /// The value to set the current checksum to + public ChecksumGeneratorBase(uint initialValue) + { + _current = initialValue; + } + + /// + /// Resets the current checksum to zero + /// + public void Reset() { _current = 0; } + + /// + /// Gets the current checksum value + /// + public uint Value { get { return _current; } } + + /// + /// Updates the current checksum with part of an array of bytes + /// + /// The data to update the checksum with + /// Where in data to start updating + /// The number of bytes from data to use + /// The sum of offset and count is larger than the length of data + /// data is a null reference + /// Offset or count is negative. + /// All the other Update methods are implmeneted in terms of this one. + /// This is therefore the only method a derived class has to implement + public abstract void Update(byte[] data, int offset, int count); + + /// + /// Updates the current checksum with an array of bytes. + /// + /// The data to update the checksum with + public void Update(byte[] data) + { + Update(data, 0, data.Length); + } + + /// + /// Updates the current checksum with the data from a string + /// + /// The string to update the checksum with + /// The characters in the string are converted by the UTF-8 encoding + public void Update(string data) + { + Update(Encoding.UTF8.GetBytes(data)); + } + + /// + /// Updates the current checksum with the data from a string, using a specific encoding + /// + /// The string to update the checksum with + /// The encoding to use + public void Update(string data, Encoding encoding) + { + Update(encoding.GetBytes(data)); + } + + } + #endregion + + #region CRC32 + /// + /// Implements a CRC32 checksum generator + /// + public sealed class CRC32Checksum : ChecksumGeneratorBase + { + #region DLL imports + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern uint crc32(uint crc, int data, uint length); + + #endregion + + /// + /// Initializes a new instance of the CRC32 checksum generator + /// + public CRC32Checksum() : base() {} + + /// + /// Initializes a new instance of the CRC32 checksum generator with a specified value + /// + /// The value to set the current checksum to + public CRC32Checksum(uint initialValue) : base(initialValue) {} + + /// + /// Updates the current checksum with part of an array of bytes + /// + /// The data to update the checksum with + /// Where in data to start updating + /// The number of bytes from data to use + /// The sum of offset and count is larger than the length of data + /// data is a null reference + /// Offset or count is negative. + public override void Update(byte[] data, int offset, int count) + { + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > data.Length) throw new ArgumentException(); + GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned); + try + { + _current = crc32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count); + } + finally + { + hData.Free(); + } + } + + } + #endregion + + #region Adler + /// + /// Implements a checksum generator that computes the Adler checksum on data + /// + public sealed class AdlerChecksum : ChecksumGeneratorBase + { + #region DLL imports + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern uint adler32(uint adler, int data, uint length); + + #endregion + + /// + /// Initializes a new instance of the Adler checksum generator + /// + public AdlerChecksum() : base() {} + + /// + /// Initializes a new instance of the Adler checksum generator with a specified value + /// + /// The value to set the current checksum to + public AdlerChecksum(uint initialValue) : base(initialValue) {} + + /// + /// Updates the current checksum with part of an array of bytes + /// + /// The data to update the checksum with + /// Where in data to start updating + /// The number of bytes from data to use + /// The sum of offset and count is larger than the length of data + /// data is a null reference + /// Offset or count is negative. + public override void Update(byte[] data, int offset, int count) + { + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > data.Length) throw new ArgumentException(); + GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned); + try + { + _current = adler32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count); + } + finally + { + hData.Free(); + } + } + + } + #endregion + +} \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/CircularBuffer.cs b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/CircularBuffer.cs new file mode 100644 index 000000000..9c8d60195 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/CircularBuffer.cs @@ -0,0 +1,83 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Diagnostics; + +namespace DotZLib +{ + + /// + /// This class implements a circular buffer + /// + internal class CircularBuffer + { + #region Private data + private int _capacity; + private int _head; + private int _tail; + private int _size; + private byte[] _buffer; + #endregion + + public CircularBuffer(int capacity) + { + Debug.Assert( capacity > 0 ); + _buffer = new byte[capacity]; + _capacity = capacity; + _head = 0; + _tail = 0; + _size = 0; + } + + public int Size { get { return _size; } } + + public int Put(byte[] source, int offset, int count) + { + Debug.Assert( count > 0 ); + int trueCount = Math.Min(count, _capacity - Size); + for (int i = 0; i < trueCount; ++i) + _buffer[(_tail+i) % _capacity] = source[offset+i]; + _tail += trueCount; + _tail %= _capacity; + _size += trueCount; + return trueCount; + } + + public bool Put(byte b) + { + if (Size == _capacity) // no room + return false; + _buffer[_tail++] = b; + _tail %= _capacity; + ++_size; + return true; + } + + public int Get(byte[] destination, int offset, int count) + { + int trueCount = Math.Min(count,Size); + for (int i = 0; i < trueCount; ++i) + destination[offset + i] = _buffer[(_head+i) % _capacity]; + _head += trueCount; + _head %= _capacity; + _size -= trueCount; + return trueCount; + } + + public int Get() + { + if (Size == 0) + return -1; + + int result = (int)_buffer[_head++ % _capacity]; + --_size; + return result; + } + + } +} diff --git a/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/CodecBase.cs b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/CodecBase.cs new file mode 100644 index 000000000..b0eb78a02 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/CodecBase.cs @@ -0,0 +1,198 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Runtime.InteropServices; + +namespace DotZLib +{ + /// + /// Implements the common functionality needed for all s + /// + public abstract class CodecBase : Codec, IDisposable + { + + #region Data members + + /// + /// Instance of the internal zlib buffer structure that is + /// passed to all functions in the zlib dll + /// + internal ZStream _ztream = new ZStream(); + + /// + /// True if the object instance has been disposed, false otherwise + /// + protected bool _isDisposed = false; + + /// + /// The size of the internal buffers + /// + protected const int kBufferSize = 16384; + + private byte[] _outBuffer = new byte[kBufferSize]; + private byte[] _inBuffer = new byte[kBufferSize]; + + private GCHandle _hInput; + private GCHandle _hOutput; + + private uint _checksum = 0; + + #endregion + + /// + /// Initializes a new instance of the CodeBase class. + /// + public CodecBase() + { + try + { + _hInput = GCHandle.Alloc(_inBuffer, GCHandleType.Pinned); + _hOutput = GCHandle.Alloc(_outBuffer, GCHandleType.Pinned); + } + catch (Exception) + { + CleanUp(false); + throw; + } + } + + + #region Codec Members + + /// + /// Occurs when more processed data are available. + /// + public event DataAvailableHandler DataAvailable; + + /// + /// Fires the event + /// + protected void OnDataAvailable() + { + if (_ztream.total_out > 0) + { + if (DataAvailable != null) + DataAvailable( _outBuffer, 0, (int)_ztream.total_out); + resetOutput(); + } + } + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// Adding data may, or may not, raise the DataAvailable event + public void Add(byte[] data) + { + Add(data,0,data.Length); + } + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// The index of the first byte to add from data + /// The number of bytes to add + /// Adding data may, or may not, raise the DataAvailable event + /// This must be implemented by a derived class + public abstract void Add(byte[] data, int offset, int count); + + /// + /// Finishes up any pending data that needs to be processed and handled. + /// + /// This must be implemented by a derived class + public abstract void Finish(); + + /// + /// Gets the checksum of the data that has been added so far + /// + public uint Checksum { get { return _checksum; } } + + #endregion + + #region Destructor & IDisposable stuff + + /// + /// Destroys this instance + /// + ~CodecBase() + { + CleanUp(false); + } + + /// + /// Releases any unmanaged resources and calls the method of the derived class + /// + public void Dispose() + { + CleanUp(true); + } + + /// + /// Performs any codec specific cleanup + /// + /// This must be implemented by a derived class + protected abstract void CleanUp(); + + // performs the release of the handles and calls the dereived CleanUp() + private void CleanUp(bool isDisposing) + { + if (!_isDisposed) + { + CleanUp(); + if (_hInput.IsAllocated) + _hInput.Free(); + if (_hOutput.IsAllocated) + _hOutput.Free(); + + _isDisposed = true; + } + } + + + #endregion + + #region Helper methods + + /// + /// Copies a number of bytes to the internal codec buffer - ready for proccesing + /// + /// The byte array that contains the data to copy + /// The index of the first byte to copy + /// The number of bytes to copy from data + protected void copyInput(byte[] data, int startIndex, int count) + { + Array.Copy(data, startIndex, _inBuffer,0, count); + _ztream.next_in = _hInput.AddrOfPinnedObject(); + _ztream.total_in = 0; + _ztream.avail_in = (uint)count; + + } + + /// + /// Resets the internal output buffers to a known state - ready for processing + /// + protected void resetOutput() + { + _ztream.total_out = 0; + _ztream.avail_out = kBufferSize; + _ztream.next_out = _hOutput.AddrOfPinnedObject(); + } + + /// + /// Updates the running checksum property + /// + /// The new checksum value + protected void setChecksum(uint newSum) + { + _checksum = newSum; + } + #endregion + + } +} diff --git a/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/Deflater.cs b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/Deflater.cs new file mode 100644 index 000000000..9039f41f6 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/Deflater.cs @@ -0,0 +1,106 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace DotZLib +{ + + /// + /// Implements a data compressor, using the deflate algorithm in the ZLib dll + /// + public sealed class Deflater : CodecBase + { + #region Dll imports + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)] + private static extern int deflateInit_(ref ZStream sz, int level, string vs, int size); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int deflate(ref ZStream sz, int flush); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int deflateReset(ref ZStream sz); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int deflateEnd(ref ZStream sz); + #endregion + + /// + /// Constructs an new instance of the Deflater + /// + /// The compression level to use for this Deflater + public Deflater(CompressLevel level) : base() + { + int retval = deflateInit_(ref _ztream, (int)level, Info.Version, Marshal.SizeOf(_ztream)); + if (retval != 0) + throw new ZLibException(retval, "Could not initialize deflater"); + + resetOutput(); + } + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// The index of the first byte to add from data + /// The number of bytes to add + /// Adding data may, or may not, raise the DataAvailable event + public override void Add(byte[] data, int offset, int count) + { + if (data == null) throw new ArgumentNullException(); + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > data.Length) throw new ArgumentException(); + + int total = count; + int inputIndex = offset; + int err = 0; + + while (err >= 0 && inputIndex < total) + { + copyInput(data, inputIndex, Math.Min(total - inputIndex, kBufferSize)); + while (err >= 0 && _ztream.avail_in > 0) + { + err = deflate(ref _ztream, (int)FlushTypes.None); + if (err == 0) + while (_ztream.avail_out == 0) + { + OnDataAvailable(); + err = deflate(ref _ztream, (int)FlushTypes.None); + } + inputIndex += (int)_ztream.total_in; + } + } + setChecksum( _ztream.adler ); + } + + + /// + /// Finishes up any pending data that needs to be processed and handled. + /// + public override void Finish() + { + int err; + do + { + err = deflate(ref _ztream, (int)FlushTypes.Finish); + OnDataAvailable(); + } + while (err == 0); + setChecksum( _ztream.adler ); + deflateReset(ref _ztream); + resetOutput(); + } + + /// + /// Closes the internal zlib deflate stream + /// + protected override void CleanUp() { deflateEnd(ref _ztream); } + + } +} diff --git a/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/DotZLib.cs b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/DotZLib.cs new file mode 100644 index 000000000..90c7c3b38 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/DotZLib.cs @@ -0,0 +1,288 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + + +namespace DotZLib +{ + + #region Internal types + + /// + /// Defines constants for the various flush types used with zlib + /// + internal enum FlushTypes + { + None, Partial, Sync, Full, Finish, Block + } + + #region ZStream structure + // internal mapping of the zlib zstream structure for marshalling + [StructLayoutAttribute(LayoutKind.Sequential, Pack=4, Size=0, CharSet=CharSet.Ansi)] + internal struct ZStream + { + public IntPtr next_in; + public uint avail_in; + public uint total_in; + + public IntPtr next_out; + public uint avail_out; + public uint total_out; + + [MarshalAs(UnmanagedType.LPStr)] + string msg; + uint state; + + uint zalloc; + uint zfree; + uint opaque; + + int data_type; + public uint adler; + uint reserved; + } + + #endregion + + #endregion + + #region Public enums + /// + /// Defines constants for the available compression levels in zlib + /// + public enum CompressLevel : int + { + /// + /// The default compression level with a reasonable compromise between compression and speed + /// + Default = -1, + /// + /// No compression at all. The data are passed straight through. + /// + None = 0, + /// + /// The maximum compression rate available. + /// + Best = 9, + /// + /// The fastest available compression level. + /// + Fastest = 1 + } + #endregion + + #region Exception classes + /// + /// The exception that is thrown when an error occurs on the zlib dll + /// + public class ZLibException : ApplicationException + { + /// + /// Initializes a new instance of the class with a specified + /// error message and error code + /// + /// The zlib error code that caused the exception + /// A message that (hopefully) describes the error + public ZLibException(int errorCode, string msg) : base(String.Format("ZLib error {0} {1}", errorCode, msg)) + { + } + + /// + /// Initializes a new instance of the class with a specified + /// error code + /// + /// The zlib error code that caused the exception + public ZLibException(int errorCode) : base(String.Format("ZLib error {0}", errorCode)) + { + } + } + #endregion + + #region Interfaces + + /// + /// Declares methods and properties that enables a running checksum to be calculated + /// + public interface ChecksumGenerator + { + /// + /// Gets the current value of the checksum + /// + uint Value { get; } + + /// + /// Clears the current checksum to 0 + /// + void Reset(); + + /// + /// Updates the current checksum with an array of bytes + /// + /// The data to update the checksum with + void Update(byte[] data); + + /// + /// Updates the current checksum with part of an array of bytes + /// + /// The data to update the checksum with + /// Where in data to start updating + /// The number of bytes from data to use + /// The sum of offset and count is larger than the length of data + /// data is a null reference + /// Offset or count is negative. + void Update(byte[] data, int offset, int count); + + /// + /// Updates the current checksum with the data from a string + /// + /// The string to update the checksum with + /// The characters in the string are converted by the UTF-8 encoding + void Update(string data); + + /// + /// Updates the current checksum with the data from a string, using a specific encoding + /// + /// The string to update the checksum with + /// The encoding to use + void Update(string data, Encoding encoding); + } + + + /// + /// Represents the method that will be called from a codec when new data + /// are available. + /// + /// The byte array containing the processed data + /// The index of the first processed byte in data + /// The number of processed bytes available + /// On return from this method, the data may be overwritten, so grab it while you can. + /// You cannot assume that startIndex will be zero. + /// + public delegate void DataAvailableHandler(byte[] data, int startIndex, int count); + + /// + /// Declares methods and events for implementing compressors/decompressors + /// + public interface Codec + { + /// + /// Occurs when more processed data are available. + /// + event DataAvailableHandler DataAvailable; + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// Adding data may, or may not, raise the DataAvailable event + void Add(byte[] data); + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// The index of the first byte to add from data + /// The number of bytes to add + /// Adding data may, or may not, raise the DataAvailable event + void Add(byte[] data, int offset, int count); + + /// + /// Finishes up any pending data that needs to be processed and handled. + /// + void Finish(); + + /// + /// Gets the checksum of the data that has been added so far + /// + uint Checksum { get; } + + + } + + #endregion + + #region Classes + /// + /// Encapsulates general information about the ZLib library + /// + public class Info + { + #region DLL imports + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern uint zlibCompileFlags(); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern string zlibVersion(); + #endregion + + #region Private stuff + private uint _flags; + + // helper function that unpacks a bitsize mask + private static int bitSize(uint bits) + { + switch (bits) + { + case 0: return 16; + case 1: return 32; + case 2: return 64; + } + return -1; + } + #endregion + + /// + /// Constructs an instance of the Info class. + /// + public Info() + { + _flags = zlibCompileFlags(); + } + + /// + /// True if the library is compiled with debug info + /// + public bool HasDebugInfo { get { return 0 != (_flags & 0x100); } } + + /// + /// True if the library is compiled with assembly optimizations + /// + public bool UsesAssemblyCode { get { return 0 != (_flags & 0x200); } } + + /// + /// Gets the size of the unsigned int that was compiled into Zlib + /// + public int SizeOfUInt { get { return bitSize(_flags & 3); } } + + /// + /// Gets the size of the unsigned long that was compiled into Zlib + /// + public int SizeOfULong { get { return bitSize((_flags >> 2) & 3); } } + + /// + /// Gets the size of the pointers that were compiled into Zlib + /// + public int SizeOfPointer { get { return bitSize((_flags >> 4) & 3); } } + + /// + /// Gets the size of the z_off_t type that was compiled into Zlib + /// + public int SizeOfOffset { get { return bitSize((_flags >> 6) & 3); } } + + /// + /// Gets the version of ZLib as a string, e.g. "1.2.1" + /// + public static string Version { get { return zlibVersion(); } } + } + + #endregion + +} diff --git a/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/DotZLib.csproj b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/DotZLib.csproj new file mode 100644 index 000000000..dea7fb16a --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/DotZLib.csproj @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/GZipStream.cs b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/GZipStream.cs new file mode 100644 index 000000000..f0eada1d2 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/GZipStream.cs @@ -0,0 +1,301 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace DotZLib +{ + /// + /// Implements a compressed , in GZip (.gz) format. + /// + public class GZipStream : Stream, IDisposable + { + #region Dll Imports + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)] + private static extern IntPtr gzopen(string name, string mode); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int gzclose(IntPtr gzFile); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int gzwrite(IntPtr gzFile, int data, int length); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int gzread(IntPtr gzFile, int data, int length); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int gzgetc(IntPtr gzFile); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int gzputc(IntPtr gzFile, int c); + + #endregion + + #region Private data + private IntPtr _gzFile; + private bool _isDisposed = false; + private bool _isWriting; + #endregion + + #region Constructors + /// + /// Creates a new file as a writeable GZipStream + /// + /// The name of the compressed file to create + /// The compression level to use when adding data + /// If an error occurred in the internal zlib function + public GZipStream(string fileName, CompressLevel level) + { + _isWriting = true; + _gzFile = gzopen(fileName, String.Format("wb{0}", (int)level)); + if (_gzFile == IntPtr.Zero) + throw new ZLibException(-1, "Could not open " + fileName); + } + + /// + /// Opens an existing file as a readable GZipStream + /// + /// The name of the file to open + /// If an error occurred in the internal zlib function + public GZipStream(string fileName) + { + _isWriting = false; + _gzFile = gzopen(fileName, "rb"); + if (_gzFile == IntPtr.Zero) + throw new ZLibException(-1, "Could not open " + fileName); + + } + #endregion + + #region Access properties + /// + /// Returns true of this stream can be read from, false otherwise + /// + public override bool CanRead + { + get + { + return !_isWriting; + } + } + + + /// + /// Returns false. + /// + public override bool CanSeek + { + get + { + return false; + } + } + + /// + /// Returns true if this tsream is writeable, false otherwise + /// + public override bool CanWrite + { + get + { + return _isWriting; + } + } + #endregion + + #region Destructor & IDispose stuff + + /// + /// Destroys this instance + /// + ~GZipStream() + { + cleanUp(false); + } + + /// + /// Closes the external file handle + /// + public void Dispose() + { + cleanUp(true); + } + + // Does the actual closing of the file handle. + private void cleanUp(bool isDisposing) + { + if (!_isDisposed) + { + gzclose(_gzFile); + _isDisposed = true; + } + } + #endregion + + #region Basic reading and writing + /// + /// Attempts to read a number of bytes from the stream. + /// + /// The destination data buffer + /// The index of the first destination byte in buffer + /// The number of bytes requested + /// The number of bytes read + /// If buffer is null + /// If count or offset are negative + /// If offset + count is > buffer.Length + /// If this stream is not readable. + /// If this stream has been disposed. + public override int Read(byte[] buffer, int offset, int count) + { + if (!CanRead) throw new NotSupportedException(); + if (buffer == null) throw new ArgumentNullException(); + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > buffer.Length) throw new ArgumentException(); + if (_isDisposed) throw new ObjectDisposedException("GZipStream"); + + GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned); + int result; + try + { + result = gzread(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count); + if (result < 0) + throw new IOException(); + } + finally + { + h.Free(); + } + return result; + } + + /// + /// Attempts to read a single byte from the stream. + /// + /// The byte that was read, or -1 in case of error or End-Of-File + public override int ReadByte() + { + if (!CanRead) throw new NotSupportedException(); + if (_isDisposed) throw new ObjectDisposedException("GZipStream"); + return gzgetc(_gzFile); + } + + /// + /// Writes a number of bytes to the stream + /// + /// + /// + /// + /// If buffer is null + /// If count or offset are negative + /// If offset + count is > buffer.Length + /// If this stream is not writeable. + /// If this stream has been disposed. + public override void Write(byte[] buffer, int offset, int count) + { + if (!CanWrite) throw new NotSupportedException(); + if (buffer == null) throw new ArgumentNullException(); + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > buffer.Length) throw new ArgumentException(); + if (_isDisposed) throw new ObjectDisposedException("GZipStream"); + + GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned); + try + { + int result = gzwrite(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count); + if (result < 0) + throw new IOException(); + } + finally + { + h.Free(); + } + } + + /// + /// Writes a single byte to the stream + /// + /// The byte to add to the stream. + /// If this stream is not writeable. + /// If this stream has been disposed. + public override void WriteByte(byte value) + { + if (!CanWrite) throw new NotSupportedException(); + if (_isDisposed) throw new ObjectDisposedException("GZipStream"); + + int result = gzputc(_gzFile, (int)value); + if (result < 0) + throw new IOException(); + } + #endregion + + #region Position & length stuff + /// + /// Not supported. + /// + /// + /// Always thrown + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + /// + /// Not suppported. + /// + /// + /// + /// + /// Always thrown + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + + /// + /// Flushes the GZipStream. + /// + /// In this implementation, this method does nothing. This is because excessive + /// flushing may degrade the achievable compression rates. + public override void Flush() + { + // left empty on purpose + } + + /// + /// Gets/sets the current position in the GZipStream. Not suppported. + /// + /// In this implementation this property is not supported + /// Always thrown + public override long Position + { + get + { + throw new NotSupportedException(); + } + set + { + throw new NotSupportedException(); + } + } + + /// + /// Gets the size of the stream. Not suppported. + /// + /// In this implementation this property is not supported + /// Always thrown + public override long Length + { + get + { + throw new NotSupportedException(); + } + } + #endregion + } +} diff --git a/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/Inflater.cs b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/Inflater.cs new file mode 100644 index 000000000..d295f2680 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/Inflater.cs @@ -0,0 +1,105 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace DotZLib +{ + + /// + /// Implements a data decompressor, using the inflate algorithm in the ZLib dll + /// + public class Inflater : CodecBase + { + #region Dll imports + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)] + private static extern int inflateInit_(ref ZStream sz, string vs, int size); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int inflate(ref ZStream sz, int flush); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int inflateReset(ref ZStream sz); + + [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)] + private static extern int inflateEnd(ref ZStream sz); + #endregion + + /// + /// Constructs an new instance of the Inflater + /// + public Inflater() : base() + { + int retval = inflateInit_(ref _ztream, Info.Version, Marshal.SizeOf(_ztream)); + if (retval != 0) + throw new ZLibException(retval, "Could not initialize inflater"); + + resetOutput(); + } + + + /// + /// Adds more data to the codec to be processed. + /// + /// Byte array containing the data to be added to the codec + /// The index of the first byte to add from data + /// The number of bytes to add + /// Adding data may, or may not, raise the DataAvailable event + public override void Add(byte[] data, int offset, int count) + { + if (data == null) throw new ArgumentNullException(); + if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException(); + if ((offset+count) > data.Length) throw new ArgumentException(); + + int total = count; + int inputIndex = offset; + int err = 0; + + while (err >= 0 && inputIndex < total) + { + copyInput(data, inputIndex, Math.Min(total - inputIndex, kBufferSize)); + err = inflate(ref _ztream, (int)FlushTypes.None); + if (err == 0) + while (_ztream.avail_out == 0) + { + OnDataAvailable(); + err = inflate(ref _ztream, (int)FlushTypes.None); + } + + inputIndex += (int)_ztream.total_in; + } + setChecksum( _ztream.adler ); + } + + + /// + /// Finishes up any pending data that needs to be processed and handled. + /// + public override void Finish() + { + int err; + do + { + err = inflate(ref _ztream, (int)FlushTypes.Finish); + OnDataAvailable(); + } + while (err == 0); + setChecksum( _ztream.adler ); + inflateReset(ref _ztream); + resetOutput(); + } + + /// + /// Closes the internal zlib inflate stream + /// + protected override void CleanUp() { inflateEnd(ref _ztream); } + + + } +} diff --git a/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/UnitTests.cs b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/UnitTests.cs new file mode 100644 index 000000000..153946140 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/dotzlib/DotZLib/UnitTests.cs @@ -0,0 +1,274 @@ +// +// © Copyright Henrik Ravn 2004 +// +// Use, modification and distribution are subject to the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +using System; +using System.Collections; +using System.IO; + +// uncomment the define below to include unit tests +//#define nunit +#if nunit +using NUnit.Framework; + +// Unit tests for the DotZLib class library +// ---------------------------------------- +// +// Use this with NUnit 2 from http://www.nunit.org +// + +namespace DotZLibTests +{ + using DotZLib; + + // helper methods + internal class Utils + { + public static bool byteArrEqual( byte[] lhs, byte[] rhs ) + { + if (lhs.Length != rhs.Length) + return false; + for (int i = lhs.Length-1; i >= 0; --i) + if (lhs[i] != rhs[i]) + return false; + return true; + } + + } + + + [TestFixture] + public class CircBufferTests + { + #region Circular buffer tests + [Test] + public void SinglePutGet() + { + CircularBuffer buf = new CircularBuffer(10); + Assert.AreEqual( 0, buf.Size ); + Assert.AreEqual( -1, buf.Get() ); + + Assert.IsTrue(buf.Put( 1 )); + Assert.AreEqual( 1, buf.Size ); + Assert.AreEqual( 1, buf.Get() ); + Assert.AreEqual( 0, buf.Size ); + Assert.AreEqual( -1, buf.Get() ); + } + + [Test] + public void BlockPutGet() + { + CircularBuffer buf = new CircularBuffer(10); + byte[] arr = {1,2,3,4,5,6,7,8,9,10}; + Assert.AreEqual( 10, buf.Put(arr,0,10) ); + Assert.AreEqual( 10, buf.Size ); + Assert.IsFalse( buf.Put(11) ); + Assert.AreEqual( 1, buf.Get() ); + Assert.IsTrue( buf.Put(11) ); + + byte[] arr2 = (byte[])arr.Clone(); + Assert.AreEqual( 9, buf.Get(arr2,1,9) ); + Assert.IsTrue( Utils.byteArrEqual(arr,arr2) ); + } + + #endregion + } + + [TestFixture] + public class ChecksumTests + { + #region CRC32 Tests + [Test] + public void CRC32_Null() + { + CRC32Checksum crc32 = new CRC32Checksum(); + Assert.AreEqual( 0, crc32.Value ); + + crc32 = new CRC32Checksum(1); + Assert.AreEqual( 1, crc32.Value ); + + crc32 = new CRC32Checksum(556); + Assert.AreEqual( 556, crc32.Value ); + } + + [Test] + public void CRC32_Data() + { + CRC32Checksum crc32 = new CRC32Checksum(); + byte[] data = { 1,2,3,4,5,6,7 }; + crc32.Update(data); + Assert.AreEqual( 0x70e46888, crc32.Value ); + + crc32 = new CRC32Checksum(); + crc32.Update("penguin"); + Assert.AreEqual( 0x0e5c1a120, crc32.Value ); + + crc32 = new CRC32Checksum(1); + crc32.Update("penguin"); + Assert.AreEqual(0x43b6aa94, crc32.Value); + + } + #endregion + + #region Adler tests + + [Test] + public void Adler_Null() + { + AdlerChecksum adler = new AdlerChecksum(); + Assert.AreEqual(0, adler.Value); + + adler = new AdlerChecksum(1); + Assert.AreEqual( 1, adler.Value ); + + adler = new AdlerChecksum(556); + Assert.AreEqual( 556, adler.Value ); + } + + [Test] + public void Adler_Data() + { + AdlerChecksum adler = new AdlerChecksum(1); + byte[] data = { 1,2,3,4,5,6,7 }; + adler.Update(data); + Assert.AreEqual( 0x5b001d, adler.Value ); + + adler = new AdlerChecksum(); + adler.Update("penguin"); + Assert.AreEqual(0x0bcf02f6, adler.Value ); + + adler = new AdlerChecksum(1); + adler.Update("penguin"); + Assert.AreEqual(0x0bd602f7, adler.Value); + + } + #endregion + } + + [TestFixture] + public class InfoTests + { + #region Info tests + [Test] + public void Info_Version() + { + Info info = new Info(); + Assert.AreEqual("1.2.8", Info.Version); + Assert.AreEqual(32, info.SizeOfUInt); + Assert.AreEqual(32, info.SizeOfULong); + Assert.AreEqual(32, info.SizeOfPointer); + Assert.AreEqual(32, info.SizeOfOffset); + } + #endregion + } + + [TestFixture] + public class DeflateInflateTests + { + #region Deflate tests + [Test] + public void Deflate_Init() + { + using (Deflater def = new Deflater(CompressLevel.Default)) + { + } + } + + private ArrayList compressedData = new ArrayList(); + private uint adler1; + + private ArrayList uncompressedData = new ArrayList(); + private uint adler2; + + public void CDataAvail(byte[] data, int startIndex, int count) + { + for (int i = 0; i < count; ++i) + compressedData.Add(data[i+startIndex]); + } + + [Test] + public void Deflate_Compress() + { + compressedData.Clear(); + + byte[] testData = new byte[35000]; + for (int i = 0; i < testData.Length; ++i) + testData[i] = 5; + + using (Deflater def = new Deflater((CompressLevel)5)) + { + def.DataAvailable += new DataAvailableHandler(CDataAvail); + def.Add(testData); + def.Finish(); + adler1 = def.Checksum; + } + } + #endregion + + #region Inflate tests + [Test] + public void Inflate_Init() + { + using (Inflater inf = new Inflater()) + { + } + } + + private void DDataAvail(byte[] data, int startIndex, int count) + { + for (int i = 0; i < count; ++i) + uncompressedData.Add(data[i+startIndex]); + } + + [Test] + public void Inflate_Expand() + { + uncompressedData.Clear(); + + using (Inflater inf = new Inflater()) + { + inf.DataAvailable += new DataAvailableHandler(DDataAvail); + inf.Add((byte[])compressedData.ToArray(typeof(byte))); + inf.Finish(); + adler2 = inf.Checksum; + } + Assert.AreEqual( adler1, adler2 ); + } + #endregion + } + + [TestFixture] + public class GZipStreamTests + { + #region GZipStream test + [Test] + public void GZipStream_WriteRead() + { + using (GZipStream gzOut = new GZipStream("gzstream.gz", CompressLevel.Best)) + { + BinaryWriter writer = new BinaryWriter(gzOut); + writer.Write("hi there"); + writer.Write(Math.PI); + writer.Write(42); + } + + using (GZipStream gzIn = new GZipStream("gzstream.gz")) + { + BinaryReader reader = new BinaryReader(gzIn); + string s = reader.ReadString(); + Assert.AreEqual("hi there",s); + double d = reader.ReadDouble(); + Assert.AreEqual(Math.PI, d); + int i = reader.ReadInt32(); + Assert.AreEqual(42,i); + } + + } + #endregion + } +} + +#endif diff --git a/test/zlib/zlib-1.2.8/contrib/dotzlib/LICENSE_1_0.txt b/test/zlib/zlib-1.2.8/contrib/dotzlib/LICENSE_1_0.txt new file mode 100644 index 000000000..127a5bc39 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/dotzlib/LICENSE_1_0.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/dotzlib/readme.txt b/test/zlib/zlib-1.2.8/contrib/dotzlib/readme.txt new file mode 100644 index 000000000..4d8c2dd93 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/dotzlib/readme.txt @@ -0,0 +1,58 @@ +This directory contains a .Net wrapper class library for the ZLib1.dll + +The wrapper includes support for inflating/deflating memory buffers, +.Net streaming wrappers for the gz streams part of zlib, and wrappers +for the checksum parts of zlib. See DotZLib/UnitTests.cs for examples. + +Directory structure: +-------------------- + +LICENSE_1_0.txt - License file. +readme.txt - This file. +DotZLib.chm - Class library documentation +DotZLib.build - NAnt build file +DotZLib.sln - Microsoft Visual Studio 2003 solution file + +DotZLib\*.cs - Source files for the class library + +Unit tests: +----------- +The file DotZLib/UnitTests.cs contains unit tests for use with NUnit 2.1 or higher. +To include unit tests in the build, define nunit before building. + + +Build instructions: +------------------- + +1. Using Visual Studio.Net 2003: + Open DotZLib.sln in VS.Net and build from there. Output file (DotZLib.dll) + will be found ./DotZLib/bin/release or ./DotZLib/bin/debug, depending on + you are building the release or debug version of the library. Check + DotZLib/UnitTests.cs for instructions on how to include unit tests in the + build. + +2. Using NAnt: + Open a command prompt with access to the build environment and run nant + in the same directory as the DotZLib.build file. + You can define 2 properties on the nant command-line to control the build: + debug={true|false} to toggle between release/debug builds (default=true). + nunit={true|false} to include or esclude unit tests (default=true). + Also the target clean will remove binaries. + Output file (DotZLib.dll) will be found in either ./DotZLib/bin/release + or ./DotZLib/bin/debug, depending on whether you are building the release + or debug version of the library. + + Examples: + nant -D:debug=false -D:nunit=false + will build a release mode version of the library without unit tests. + nant + will build a debug version of the library with unit tests + nant clean + will remove all previously built files. + + +--------------------------------- +Copyright (c) Henrik Ravn 2004 + +Use, modification and distribution are subject to the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/test/zlib/zlib-1.2.8/contrib/gcc_gvmat64/gvmat64.S b/test/zlib/zlib-1.2.8/contrib/gcc_gvmat64/gvmat64.S new file mode 100644 index 000000000..23309fa28 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/gcc_gvmat64/gvmat64.S @@ -0,0 +1,574 @@ +/* +;uInt longest_match_x64( +; deflate_state *s, +; IPos cur_match); // current match + +; gvmat64.S -- Asm portion of the optimized longest_match for 32 bits x86_64 +; (AMD64 on Athlon 64, Opteron, Phenom +; and Intel EM64T on Pentium 4 with EM64T, Pentium D, Core 2 Duo, Core I5/I7) +; this file is translation from gvmat64.asm to GCC 4.x (for Linux, Mac XCode) +; Copyright (C) 1995-2010 Jean-loup Gailly, Brian Raiter and Gilles Vollant. +; +; File written by Gilles Vollant, by converting to assembly the longest_match +; from Jean-loup Gailly in deflate.c of zLib and infoZip zip. +; and by taking inspiration on asm686 with masm, optimised assembly code +; from Brian Raiter, written 1998 +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must not +; claim that you wrote the original software. If you use this software +; in a product, an acknowledgment in the product documentation would be +; appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must not be +; misrepresented as being the original software +; 3. This notice may not be removed or altered from any source distribution. +; +; http://www.zlib.net +; http://www.winimage.com/zLibDll +; http://www.muppetlabs.com/~breadbox/software/assembly.html +; +; to compile this file for zLib, I use option: +; gcc -c -arch x86_64 gvmat64.S + + +;uInt longest_match(s, cur_match) +; deflate_state *s; +; IPos cur_match; // current match / +; +; with XCode for Mac, I had strange error with some jump on intel syntax +; this is why BEFORE_JMP and AFTER_JMP are used + */ + + +#define BEFORE_JMP .att_syntax +#define AFTER_JMP .intel_syntax noprefix + +#ifndef NO_UNDERLINE +# define match_init _match_init +# define longest_match _longest_match +#endif + +.intel_syntax noprefix + +.globl match_init, longest_match +.text +longest_match: + + + +#define LocalVarsSize 96 +/* +; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12 +; free register : r14,r15 +; register can be saved : rsp +*/ + +#define chainlenwmask (rsp + 8 - LocalVarsSize) +#define nicematch (rsp + 16 - LocalVarsSize) + +#define save_rdi (rsp + 24 - LocalVarsSize) +#define save_rsi (rsp + 32 - LocalVarsSize) +#define save_rbx (rsp + 40 - LocalVarsSize) +#define save_rbp (rsp + 48 - LocalVarsSize) +#define save_r12 (rsp + 56 - LocalVarsSize) +#define save_r13 (rsp + 64 - LocalVarsSize) +#define save_r14 (rsp + 72 - LocalVarsSize) +#define save_r15 (rsp + 80 - LocalVarsSize) + + +/* +; all the +4 offsets are due to the addition of pending_buf_size (in zlib +; in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, remove the +4). +; Note : these value are good with a 8 bytes boundary pack structure +*/ + +#define MAX_MATCH 258 +#define MIN_MATCH 3 +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) + +/* +;;; Offsets for fields in the deflate_state structure. These numbers +;;; are calculated from the definition of deflate_state, with the +;;; assumption that the compiler will dword-align the fields. (Thus, +;;; changing the definition of deflate_state could easily cause this +;;; program to crash horribly, without so much as a warning at +;;; compile time. Sigh.) + +; all the +zlib1222add offsets are due to the addition of fields +; in zlib in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). +; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). +; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). +*/ + + + +/* you can check the structure offset by running + +#include +#include +#include "deflate.h" + +void print_depl() +{ +deflate_state ds; +deflate_state *s=&ds; +printf("size pointer=%u\n",(int)sizeof(void*)); + +printf("#define dsWSize %u\n",(int)(((char*)&(s->w_size))-((char*)s))); +printf("#define dsWMask %u\n",(int)(((char*)&(s->w_mask))-((char*)s))); +printf("#define dsWindow %u\n",(int)(((char*)&(s->window))-((char*)s))); +printf("#define dsPrev %u\n",(int)(((char*)&(s->prev))-((char*)s))); +printf("#define dsMatchLen %u\n",(int)(((char*)&(s->match_length))-((char*)s))); +printf("#define dsPrevMatch %u\n",(int)(((char*)&(s->prev_match))-((char*)s))); +printf("#define dsStrStart %u\n",(int)(((char*)&(s->strstart))-((char*)s))); +printf("#define dsMatchStart %u\n",(int)(((char*)&(s->match_start))-((char*)s))); +printf("#define dsLookahead %u\n",(int)(((char*)&(s->lookahead))-((char*)s))); +printf("#define dsPrevLen %u\n",(int)(((char*)&(s->prev_length))-((char*)s))); +printf("#define dsMaxChainLen %u\n",(int)(((char*)&(s->max_chain_length))-((char*)s))); +printf("#define dsGoodMatch %u\n",(int)(((char*)&(s->good_match))-((char*)s))); +printf("#define dsNiceMatch %u\n",(int)(((char*)&(s->nice_match))-((char*)s))); +} +*/ + +#define dsWSize 68 +#define dsWMask 76 +#define dsWindow 80 +#define dsPrev 96 +#define dsMatchLen 144 +#define dsPrevMatch 148 +#define dsStrStart 156 +#define dsMatchStart 160 +#define dsLookahead 164 +#define dsPrevLen 168 +#define dsMaxChainLen 172 +#define dsGoodMatch 188 +#define dsNiceMatch 192 + +#define window_size [ rcx + dsWSize] +#define WMask [ rcx + dsWMask] +#define window_ad [ rcx + dsWindow] +#define prev_ad [ rcx + dsPrev] +#define strstart [ rcx + dsStrStart] +#define match_start [ rcx + dsMatchStart] +#define Lookahead [ rcx + dsLookahead] //; 0ffffffffh on infozip +#define prev_length [ rcx + dsPrevLen] +#define max_chain_length [ rcx + dsMaxChainLen] +#define good_match [ rcx + dsGoodMatch] +#define nice_match [ rcx + dsNiceMatch] + +/* +; windows: +; parameter 1 in rcx(deflate state s), param 2 in rdx (cur match) + +; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and +; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp +; +; All registers must be preserved across the call, except for +; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch. + +; +; gcc on macosx-linux: +; see http://www.x86-64.org/documentation/abi-0.99.pdf +; param 1 in rdi, param 2 in rsi +; rbx, rsp, rbp, r12 to r15 must be preserved + +;;; Save registers that the compiler may be using, and adjust esp to +;;; make room for our stack frame. + + +;;; Retrieve the function arguments. r8d will hold cur_match +;;; throughout the entire function. edx will hold the pointer to the +;;; deflate_state structure during the function's setup (before +;;; entering the main loop. + +; ms: parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match) +; mac: param 1 in rdi, param 2 rsi +; this clear high 32 bits of r8, which can be garbage in both r8 and rdx +*/ + mov [save_rbx],rbx + mov [save_rbp],rbp + + + mov rcx,rdi + + mov r8d,esi + + + mov [save_r12],r12 + mov [save_r13],r13 + mov [save_r14],r14 + mov [save_r15],r15 + + +//;;; uInt wmask = s->w_mask; +//;;; unsigned chain_length = s->max_chain_length; +//;;; if (s->prev_length >= s->good_match) { +//;;; chain_length >>= 2; +//;;; } + + + mov edi, prev_length + mov esi, good_match + mov eax, WMask + mov ebx, max_chain_length + cmp edi, esi + jl LastMatchGood + shr ebx, 2 +LastMatchGood: + +//;;; chainlen is decremented once beforehand so that the function can +//;;; use the sign flag instead of the zero flag for the exit test. +//;;; It is then shifted into the high word, to make room for the wmask +//;;; value, which it will always accompany. + + dec ebx + shl ebx, 16 + or ebx, eax + +//;;; on zlib only +//;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + + + mov eax, nice_match + mov [chainlenwmask], ebx + mov r10d, Lookahead + cmp r10d, eax + cmovnl r10d, eax + mov [nicematch],r10d + + + +//;;; register Bytef *scan = s->window + s->strstart; + mov r10, window_ad + mov ebp, strstart + lea r13, [r10 + rbp] + +//;;; Determine how many bytes the scan ptr is off from being +//;;; dword-aligned. + + mov r9,r13 + neg r13 + and r13,3 + +//;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? +//;;; s->strstart - (IPos)MAX_DIST(s) : NIL; + + + mov eax, window_size + sub eax, MIN_LOOKAHEAD + + + xor edi,edi + sub ebp, eax + + mov r11d, prev_length + + cmovng ebp,edi + +//;;; int best_len = s->prev_length; + + +//;;; Store the sum of s->window + best_len in esi locally, and in esi. + + lea rsi,[r10+r11] + +//;;; register ush scan_start = *(ushf*)scan; +//;;; register ush scan_end = *(ushf*)(scan+best_len-1); +//;;; Posf *prev = s->prev; + + movzx r12d,word ptr [r9] + movzx ebx, word ptr [r9 + r11 - 1] + + mov rdi, prev_ad + +//;;; Jump into the main loop. + + mov edx, [chainlenwmask] + + cmp bx,word ptr [rsi + r8 - 1] + jz LookupLoopIsZero + + + +LookupLoop1: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + + + + sub edx, 0x00010000 + BEFORE_JMP + js LeaveNow + AFTER_JMP + +LoopEntry1: + cmp bx,word ptr [rsi + r8 - 1] + BEFORE_JMP + jz LookupLoopIsZero + AFTER_JMP + +LookupLoop2: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + BEFORE_JMP + jbe LeaveNow + AFTER_JMP + sub edx, 0x00010000 + BEFORE_JMP + js LeaveNow + AFTER_JMP + +LoopEntry2: + cmp bx,word ptr [rsi + r8 - 1] + BEFORE_JMP + jz LookupLoopIsZero + AFTER_JMP + +LookupLoop4: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + BEFORE_JMP + jbe LeaveNow + AFTER_JMP + sub edx, 0x00010000 + BEFORE_JMP + js LeaveNow + AFTER_JMP + +LoopEntry4: + + cmp bx,word ptr [rsi + r8 - 1] + BEFORE_JMP + jnz LookupLoop1 + jmp LookupLoopIsZero + AFTER_JMP +/* +;;; do { +;;; match = s->window + cur_match; +;;; if (*(ushf*)(match+best_len-1) != scan_end || +;;; *(ushf*)match != scan_start) continue; +;;; [...] +;;; } while ((cur_match = prev[cur_match & wmask]) > limit +;;; && --chain_length != 0); +;;; +;;; Here is the inner loop of the function. The function will spend the +;;; majority of its time in this loop, and majority of that time will +;;; be spent in the first ten instructions. +;;; +;;; Within this loop: +;;; ebx = scanend +;;; r8d = curmatch +;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) +;;; esi = windowbestlen - i.e., (window + bestlen) +;;; edi = prev +;;; ebp = limit +*/ +.balign 16 +LookupLoop: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + BEFORE_JMP + jbe LeaveNow + AFTER_JMP + sub edx, 0x00010000 + BEFORE_JMP + js LeaveNow + AFTER_JMP + +LoopEntry: + + cmp bx,word ptr [rsi + r8 - 1] + BEFORE_JMP + jnz LookupLoop1 + AFTER_JMP +LookupLoopIsZero: + cmp r12w, word ptr [r10 + r8] + BEFORE_JMP + jnz LookupLoop1 + AFTER_JMP + + +//;;; Store the current value of chainlen. + mov [chainlenwmask], edx +/* +;;; Point edi to the string under scrutiny, and esi to the string we +;;; are hoping to match it up with. In actuality, esi and edi are +;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is +;;; initialized to -(MAX_MATCH_8 - scanalign). +*/ + lea rsi,[r8+r10] + mov rdx, 0xfffffffffffffef8 //; -(MAX_MATCH_8) + lea rsi, [rsi + r13 + 0x0108] //;MAX_MATCH_8] + lea rdi, [r9 + r13 + 0x0108] //;MAX_MATCH_8] + + prefetcht1 [rsi+rdx] + prefetcht1 [rdi+rdx] + +/* +;;; Test the strings for equality, 8 bytes at a time. At the end, +;;; adjust rdx so that it is offset to the exact byte that mismatched. +;;; +;;; We already know at this point that the first three bytes of the +;;; strings match each other, and they can be safely passed over before +;;; starting the compare loop. So what this code does is skip over 0-3 +;;; bytes, as much as necessary in order to dword-align the edi +;;; pointer. (rsi will still be misaligned three times out of four.) +;;; +;;; It should be confessed that this loop usually does not represent +;;; much of the total running time. Replacing it with a more +;;; straightforward "rep cmpsb" would not drastically degrade +;;; performance. +*/ + +LoopCmps: + mov rax, [rsi + rdx] + xor rax, [rdi + rdx] + jnz LeaveLoopCmps + + mov rax, [rsi + rdx + 8] + xor rax, [rdi + rdx + 8] + jnz LeaveLoopCmps8 + + + mov rax, [rsi + rdx + 8+8] + xor rax, [rdi + rdx + 8+8] + jnz LeaveLoopCmps16 + + add rdx,8+8+8 + + BEFORE_JMP + jnz LoopCmps + jmp LenMaximum + AFTER_JMP + +LeaveLoopCmps16: add rdx,8 +LeaveLoopCmps8: add rdx,8 +LeaveLoopCmps: + + test eax, 0x0000FFFF + jnz LenLower + + test eax,0xffffffff + + jnz LenLower32 + + add rdx,4 + shr rax,32 + or ax,ax + BEFORE_JMP + jnz LenLower + AFTER_JMP + +LenLower32: + shr eax,16 + add rdx,2 + +LenLower: + sub al, 1 + adc rdx, 0 +//;;; Calculate the length of the match. If it is longer than MAX_MATCH, +//;;; then automatically accept it as the best possible match and leave. + + lea rax, [rdi + rdx] + sub rax, r9 + cmp eax, MAX_MATCH + BEFORE_JMP + jge LenMaximum + AFTER_JMP +/* +;;; If the length of the match is not longer than the best match we +;;; have so far, then forget it and return to the lookup loop. +;/////////////////////////////////// +*/ + cmp eax, r11d + jg LongerMatch + + lea rsi,[r10+r11] + + mov rdi, prev_ad + mov edx, [chainlenwmask] + BEFORE_JMP + jmp LookupLoop + AFTER_JMP +/* +;;; s->match_start = cur_match; +;;; best_len = len; +;;; if (len >= nice_match) break; +;;; scan_end = *(ushf*)(scan+best_len-1); +*/ +LongerMatch: + mov r11d, eax + mov match_start, r8d + cmp eax, [nicematch] + BEFORE_JMP + jge LeaveNow + AFTER_JMP + + lea rsi,[r10+rax] + + movzx ebx, word ptr [r9 + rax - 1] + mov rdi, prev_ad + mov edx, [chainlenwmask] + BEFORE_JMP + jmp LookupLoop + AFTER_JMP + +//;;; Accept the current string, with the maximum possible length. + +LenMaximum: + mov r11d,MAX_MATCH + mov match_start, r8d + +//;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; +//;;; return s->lookahead; + +LeaveNow: + mov eax, Lookahead + cmp r11d, eax + cmovng eax, r11d + + + +//;;; Restore the stack and return from whence we came. + + +// mov rsi,[save_rsi] +// mov rdi,[save_rdi] + mov rbx,[save_rbx] + mov rbp,[save_rbp] + mov r12,[save_r12] + mov r13,[save_r13] + mov r14,[save_r14] + mov r15,[save_r15] + + + ret 0 +//; please don't remove this string ! +//; Your can freely use gvmat64 in any free or commercial app +//; but it is far better don't remove the string in the binary! + // db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0 + + +match_init: + ret 0 + + diff --git a/test/zlib/zlib-1.2.8/contrib/infback9/README b/test/zlib/zlib-1.2.8/contrib/infback9/README new file mode 100644 index 000000000..e75ed1329 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/infback9/README @@ -0,0 +1 @@ +See infback9.h for what this is and how to use it. diff --git a/test/zlib/zlib-1.2.8/contrib/infback9/infback9.c b/test/zlib/zlib-1.2.8/contrib/infback9/infback9.c new file mode 100644 index 000000000..05fb3e338 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/infback9/infback9.c @@ -0,0 +1,615 @@ +/* infback9.c -- inflate deflate64 data using a call-back interface + * Copyright (C) 1995-2008 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infback9.h" +#include "inftree9.h" +#include "inflate9.h" + +#define WSIZE 65536UL + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + window is a user-supplied window and output buffer that is 64K bytes. + */ +int ZEXPORT inflateBack9Init_(strm, window, version, stream_size) +z_stream FAR *strm; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == (free_func)0) strm->zfree = zcfree; + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (voidpf)state; + state->window = window; + return Z_OK; +} + +/* + Build and output length and distance decoding tables for fixed code + decoding. + */ +#ifdef MAKEFIXED +#include + +void makefixed9(void) +{ + unsigned sym, bits, low, size; + code *next, *lenfix, *distfix; + struct inflate_state state; + code fixed[544]; + + /* literal/length table */ + sym = 0; + while (sym < 144) state.lens[sym++] = 8; + while (sym < 256) state.lens[sym++] = 9; + while (sym < 280) state.lens[sym++] = 7; + while (sym < 288) state.lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table9(LENS, state.lens, 288, &(next), &(bits), state.work); + + /* distance table */ + sym = 0; + while (sym < 32) state.lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table9(DISTS, state.lens, 32, &(next), &(bits), state.work); + + /* write tables */ + puts(" /* inffix9.h -- table for decoding deflate64 fixed codes"); + puts(" * Generated automatically by makefixed9()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", lenfix[low].op, lenfix[low].bits, + lenfix[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 5) == 0) printf("\n "); + printf("{%u,%u,%d}", distfix[low].op, distfix[low].bits, + distfix[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* Macros for inflateBack(): */ + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n <= 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = window; \ + left = WSIZE; \ + wrap = 1; \ + if (out(out_desc, put, (unsigned)left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack9(strm, in, in_desc, out, out_desc) +z_stream FAR *strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have; /* available input */ + unsigned long left; /* available output */ + inflate_mode mode; /* current inflate mode */ + int lastblock; /* true if processing last block */ + int wrap; /* true if the window has wrapped */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned extra; /* extra bits needed */ + unsigned long length; /* literal or length of data to copy */ + unsigned long offset; /* distance back to copy string from */ + unsigned long copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; +#include "inffix9.h" + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + mode = TYPE; + lastblock = 0; + wrap = 0; + window = state->window; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = window; + left = WSIZE; + lencode = Z_NULL; + distcode = Z_NULL; + + /* Inflate until end of block marked as last */ + for (;;) + switch (mode) { + case TYPE: + /* determine and dispatch block type */ + if (lastblock) { + BYTEBITS(); + mode = DONE; + break; + } + NEEDBITS(3); + lastblock = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + lastblock ? " (last)" : "")); + mode = STORED; + break; + case 1: /* fixed block */ + lencode = lenfix; + lenbits = 9; + distcode = distfix; + distbits = 5; + Tracev((stderr, "inflate: fixed codes block%s\n", + lastblock ? " (last)" : "")); + mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + lastblock ? " (last)" : "")); + mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + mode = BAD; + break; + } + length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %lu\n", + length)); + INITBITS(); + + /* copy stored block from input to output */ + while (length != 0) { + copy = length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); + if (state->nlen > 286) { + strm->msg = (char *)"too many length symbols"; + mode = BAD; + break; + } + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + lencode = (code const FAR *)(state->next); + lenbits = 7; + ret = inflate_table9(CODES, state->lens, 19, &(state->next), + &(lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = lencode[BITS(lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + NEEDBITS(here.bits); + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftree9.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + lencode = (code const FAR *)(state->next); + lenbits = 9; + ret = inflate_table9(LENS, state->lens, state->nlen, + &(state->next), &(lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + mode = BAD; + break; + } + distcode = (code const FAR *)(state->next); + distbits = 6; + ret = inflate_table9(DISTS, state->lens + state->nlen, + state->ndist, &(state->next), &(distbits), + state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + mode = LEN; + + case LEN: + /* get a literal, length, or end-of-block code */ + for (;;) { + here = lencode[BITS(lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + length = (unsigned)here.val; + + /* process literal */ + if (here.op == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + ROOM(); + *put++ = (unsigned char)(length); + left--; + mode = LEN; + break; + } + + /* process end of block */ + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + mode = TYPE; + break; + } + + /* invalid code */ + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + extra = (unsigned)(here.op) & 31; + if (extra != 0) { + NEEDBITS(extra); + length += BITS(extra); + DROPBITS(extra); + } + Tracevv((stderr, "inflate: length %lu\n", length)); + + /* get distance code */ + for (;;) { + here = distcode[BITS(distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + mode = BAD; + break; + } + offset = (unsigned)here.val; + + /* get distance extra bits, if any */ + extra = (unsigned)(here.op) & 15; + if (extra != 0) { + NEEDBITS(extra); + offset += BITS(extra); + DROPBITS(extra); + } + if (offset > WSIZE - (wrap ? 0: left)) { + strm->msg = (char *)"invalid distance too far back"; + mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %lu\n", offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = WSIZE - offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - offset; + copy = left; + } + if (copy > length) copy = length; + length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < WSIZE) { + if (out(out_desc, window, (unsigned)(WSIZE - left))) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBack9End(strm) +z_stream FAR *strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/test/zlib/zlib-1.2.8/contrib/infback9/infback9.h b/test/zlib/zlib-1.2.8/contrib/infback9/infback9.h new file mode 100644 index 000000000..1073c0a38 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/infback9/infback9.h @@ -0,0 +1,37 @@ +/* infback9.h -- header for using inflateBack9 functions + * Copyright (C) 2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * This header file and associated patches provide a decoder for PKWare's + * undocumented deflate64 compression method (method 9). Use with infback9.c, + * inftree9.h, inftree9.c, and inffix9.h. These patches are not supported. + * This should be compiled with zlib, since it uses zutil.h and zutil.o. + * This code has not yet been tested on 16-bit architectures. See the + * comments in zlib.h for inflateBack() usage. These functions are used + * identically, except that there is no windowBits parameter, and a 64K + * window must be provided. Also if int's are 16 bits, then a zero for + * the third parameter of the "out" function actually means 65536UL. + * zlib.h must be included before this header file. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +ZEXTERN int ZEXPORT inflateBack9 OF((z_stream FAR *strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +ZEXTERN int ZEXPORT inflateBack9End OF((z_stream FAR *strm)); +ZEXTERN int ZEXPORT inflateBack9Init_ OF((z_stream FAR *strm, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define inflateBack9Init(strm, window) \ + inflateBack9Init_((strm), (window), \ + ZLIB_VERSION, sizeof(z_stream)) + +#ifdef __cplusplus +} +#endif diff --git a/test/zlib/zlib-1.2.8/contrib/infback9/inffix9.h b/test/zlib/zlib-1.2.8/contrib/infback9/inffix9.h new file mode 100644 index 000000000..ee5671d2d --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/infback9/inffix9.h @@ -0,0 +1,107 @@ + /* inffix9.h -- table for decoding deflate64 fixed codes + * Generated automatically by makefixed9(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{132,8,115},{130,7,31},{0,8,112}, + {0,8,48},{0,9,192},{128,7,10},{0,8,96},{0,8,32},{0,9,160}, + {0,8,0},{0,8,128},{0,8,64},{0,9,224},{128,7,6},{0,8,88}, + {0,8,24},{0,9,144},{131,7,59},{0,8,120},{0,8,56},{0,9,208}, + {129,7,17},{0,8,104},{0,8,40},{0,9,176},{0,8,8},{0,8,136}, + {0,8,72},{0,9,240},{128,7,4},{0,8,84},{0,8,20},{133,8,227}, + {131,7,43},{0,8,116},{0,8,52},{0,9,200},{129,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232}, + {128,7,8},{0,8,92},{0,8,28},{0,9,152},{132,7,83},{0,8,124}, + {0,8,60},{0,9,216},{130,7,23},{0,8,108},{0,8,44},{0,9,184}, + {0,8,12},{0,8,140},{0,8,76},{0,9,248},{128,7,3},{0,8,82}, + {0,8,18},{133,8,163},{131,7,35},{0,8,114},{0,8,50},{0,9,196}, + {129,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},{0,8,130}, + {0,8,66},{0,9,228},{128,7,7},{0,8,90},{0,8,26},{0,9,148}, + {132,7,67},{0,8,122},{0,8,58},{0,9,212},{130,7,19},{0,8,106}, + {0,8,42},{0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244}, + {128,7,5},{0,8,86},{0,8,22},{65,8,0},{131,7,51},{0,8,118}, + {0,8,54},{0,9,204},{129,7,15},{0,8,102},{0,8,38},{0,9,172}, + {0,8,6},{0,8,134},{0,8,70},{0,9,236},{128,7,9},{0,8,94}, + {0,8,30},{0,9,156},{132,7,99},{0,8,126},{0,8,62},{0,9,220}, + {130,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{133,8,131}, + {130,7,31},{0,8,113},{0,8,49},{0,9,194},{128,7,10},{0,8,97}, + {0,8,33},{0,9,162},{0,8,1},{0,8,129},{0,8,65},{0,9,226}, + {128,7,6},{0,8,89},{0,8,25},{0,9,146},{131,7,59},{0,8,121}, + {0,8,57},{0,9,210},{129,7,17},{0,8,105},{0,8,41},{0,9,178}, + {0,8,9},{0,8,137},{0,8,73},{0,9,242},{128,7,4},{0,8,85}, + {0,8,21},{144,8,3},{131,7,43},{0,8,117},{0,8,53},{0,9,202}, + {129,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133}, + {0,8,69},{0,9,234},{128,7,8},{0,8,93},{0,8,29},{0,9,154}, + {132,7,83},{0,8,125},{0,8,61},{0,9,218},{130,7,23},{0,8,109}, + {0,8,45},{0,9,186},{0,8,13},{0,8,141},{0,8,77},{0,9,250}, + {128,7,3},{0,8,83},{0,8,19},{133,8,195},{131,7,35},{0,8,115}, + {0,8,51},{0,9,198},{129,7,11},{0,8,99},{0,8,35},{0,9,166}, + {0,8,3},{0,8,131},{0,8,67},{0,9,230},{128,7,7},{0,8,91}, + {0,8,27},{0,9,150},{132,7,67},{0,8,123},{0,8,59},{0,9,214}, + {130,7,19},{0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139}, + {0,8,75},{0,9,246},{128,7,5},{0,8,87},{0,8,23},{77,8,0}, + {131,7,51},{0,8,119},{0,8,55},{0,9,206},{129,7,15},{0,8,103}, + {0,8,39},{0,9,174},{0,8,7},{0,8,135},{0,8,71},{0,9,238}, + {128,7,9},{0,8,95},{0,8,31},{0,9,158},{132,7,99},{0,8,127}, + {0,8,63},{0,9,222},{130,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80}, + {0,8,16},{132,8,115},{130,7,31},{0,8,112},{0,8,48},{0,9,193}, + {128,7,10},{0,8,96},{0,8,32},{0,9,161},{0,8,0},{0,8,128}, + {0,8,64},{0,9,225},{128,7,6},{0,8,88},{0,8,24},{0,9,145}, + {131,7,59},{0,8,120},{0,8,56},{0,9,209},{129,7,17},{0,8,104}, + {0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},{0,9,241}, + {128,7,4},{0,8,84},{0,8,20},{133,8,227},{131,7,43},{0,8,116}, + {0,8,52},{0,9,201},{129,7,13},{0,8,100},{0,8,36},{0,9,169}, + {0,8,4},{0,8,132},{0,8,68},{0,9,233},{128,7,8},{0,8,92}, + {0,8,28},{0,9,153},{132,7,83},{0,8,124},{0,8,60},{0,9,217}, + {130,7,23},{0,8,108},{0,8,44},{0,9,185},{0,8,12},{0,8,140}, + {0,8,76},{0,9,249},{128,7,3},{0,8,82},{0,8,18},{133,8,163}, + {131,7,35},{0,8,114},{0,8,50},{0,9,197},{129,7,11},{0,8,98}, + {0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {128,7,7},{0,8,90},{0,8,26},{0,9,149},{132,7,67},{0,8,122}, + {0,8,58},{0,9,213},{130,7,19},{0,8,106},{0,8,42},{0,9,181}, + {0,8,10},{0,8,138},{0,8,74},{0,9,245},{128,7,5},{0,8,86}, + {0,8,22},{65,8,0},{131,7,51},{0,8,118},{0,8,54},{0,9,205}, + {129,7,15},{0,8,102},{0,8,38},{0,9,173},{0,8,6},{0,8,134}, + {0,8,70},{0,9,237},{128,7,9},{0,8,94},{0,8,30},{0,9,157}, + {132,7,99},{0,8,126},{0,8,62},{0,9,221},{130,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253}, + {96,7,0},{0,8,81},{0,8,17},{133,8,131},{130,7,31},{0,8,113}, + {0,8,49},{0,9,195},{128,7,10},{0,8,97},{0,8,33},{0,9,163}, + {0,8,1},{0,8,129},{0,8,65},{0,9,227},{128,7,6},{0,8,89}, + {0,8,25},{0,9,147},{131,7,59},{0,8,121},{0,8,57},{0,9,211}, + {129,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},{0,8,137}, + {0,8,73},{0,9,243},{128,7,4},{0,8,85},{0,8,21},{144,8,3}, + {131,7,43},{0,8,117},{0,8,53},{0,9,203},{129,7,13},{0,8,101}, + {0,8,37},{0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235}, + {128,7,8},{0,8,93},{0,8,29},{0,9,155},{132,7,83},{0,8,125}, + {0,8,61},{0,9,219},{130,7,23},{0,8,109},{0,8,45},{0,9,187}, + {0,8,13},{0,8,141},{0,8,77},{0,9,251},{128,7,3},{0,8,83}, + {0,8,19},{133,8,195},{131,7,35},{0,8,115},{0,8,51},{0,9,199}, + {129,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{128,7,7},{0,8,91},{0,8,27},{0,9,151}, + {132,7,67},{0,8,123},{0,8,59},{0,9,215},{130,7,19},{0,8,107}, + {0,8,43},{0,9,183},{0,8,11},{0,8,139},{0,8,75},{0,9,247}, + {128,7,5},{0,8,87},{0,8,23},{77,8,0},{131,7,51},{0,8,119}, + {0,8,55},{0,9,207},{129,7,15},{0,8,103},{0,8,39},{0,9,175}, + {0,8,7},{0,8,135},{0,8,71},{0,9,239},{128,7,9},{0,8,95}, + {0,8,31},{0,9,159},{132,7,99},{0,8,127},{0,8,63},{0,9,223}, + {130,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143}, + {0,8,79},{0,9,255} + }; + + static const code distfix[32] = { + {128,5,1},{135,5,257},{131,5,17},{139,5,4097},{129,5,5}, + {137,5,1025},{133,5,65},{141,5,16385},{128,5,3},{136,5,513}, + {132,5,33},{140,5,8193},{130,5,9},{138,5,2049},{134,5,129}, + {142,5,32769},{128,5,2},{135,5,385},{131,5,25},{139,5,6145}, + {129,5,7},{137,5,1537},{133,5,97},{141,5,24577},{128,5,4}, + {136,5,769},{132,5,49},{140,5,12289},{130,5,13},{138,5,3073}, + {134,5,193},{142,5,49153} + }; diff --git a/test/zlib/zlib-1.2.8/contrib/infback9/inflate9.h b/test/zlib/zlib-1.2.8/contrib/infback9/inflate9.h new file mode 100644 index 000000000..ee9a79394 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/infback9/inflate9.h @@ -0,0 +1,47 @@ +/* inflate9.h -- internal inflate state definition + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Possible inflate modes between inflate() calls */ +typedef enum { + TYPE, /* i: waiting for type bits, including last-flag bit */ + STORED, /* i: waiting for stored size (length and complement) */ + TABLE, /* i: waiting for dynamic block table lengths */ + LEN, /* i: waiting for length/lit code */ + DONE, /* finished check, done -- remain here until reset */ + BAD /* got a data error -- remain here until reset */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to the BAD mode -- not shown for clarity) + + Read deflate blocks: + TYPE -> STORED or TABLE or LEN or DONE + STORED -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN + Read deflate codes: + LEN -> LEN or TYPE + */ + +/* state maintained between inflate() calls. Approximately 7K bytes. */ +struct inflate_state { + /* sliding window */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ +}; diff --git a/test/zlib/zlib-1.2.8/contrib/infback9/inftree9.c b/test/zlib/zlib-1.2.8/contrib/infback9/inftree9.c new file mode 100644 index 000000000..4a73ad215 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/infback9/inftree9.c @@ -0,0 +1,324 @@ +/* inftree9.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2013 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftree9.h" + +#define MAXBITS 15 + +const char inflate9_copyright[] = + " inflate9 1.2.8 Copyright 1995-2013 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int inflate_table9(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code this; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, + 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, + 131, 163, 195, 227, 3, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, + 130, 130, 130, 130, 131, 131, 131, 131, 132, 132, 132, 132, + 133, 133, 133, 133, 144, 72, 78}; + static const unsigned short dbase[32] = { /* Distance codes 0..31 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, + 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, + 4097, 6145, 8193, 12289, 16385, 24577, 32769, 49153}; + static const unsigned short dext[32] = { /* Distance codes 0..31 extra */ + 128, 128, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132, + 133, 133, 134, 134, 135, 135, 136, 136, 137, 137, 138, 138, + 139, 139, 140, 140, 141, 141, 142, 142}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) return -1; /* no codes! */ + for (min = 1; min <= MAXBITS; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftree9.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used >= ENOUGH_LENS) || + (type == DISTS && used >= ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + this.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + this.op = (unsigned char)0; + this.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + this.op = (unsigned char)(extra[work[sym]]); + this.val = base[work[sym]]; + } + else { + this.op = (unsigned char)(32 + 64); /* end of block */ + this.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + do { + fill -= incr; + next[(huff >> drop) + fill] = this; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += 1U << curr; + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used >= ENOUGH_LENS) || + (type == DISTS && used >= ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* + Fill in rest of table for incomplete codes. This loop is similar to the + loop above in incrementing huff for table indices. It is assumed that + len is equal to curr + drop, so there is no loop needed to increment + through high index bits. When the current sub-table is filled, the loop + drops back to the root table to fill in any remaining entries there. + */ + this.op = (unsigned char)64; /* invalid code marker */ + this.bits = (unsigned char)(len - drop); + this.val = (unsigned short)0; + while (huff != 0) { + /* when done with sub-table, drop back to root table */ + if (drop != 0 && (huff & mask) != low) { + drop = 0; + len = root; + next = *table; + curr = root; + this.bits = (unsigned char)len; + } + + /* put invalid code marker in table */ + next[huff >> drop] = this; + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/test/zlib/zlib-1.2.8/contrib/infback9/inftree9.h b/test/zlib/zlib-1.2.8/contrib/infback9/inftree9.h new file mode 100644 index 000000000..5ab21f0c6 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/infback9/inftree9.h @@ -0,0 +1,61 @@ +/* inftree9.h -- header to use inftree9.c + * Copyright (C) 1995-2008 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 100eeeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1446, which is the sum of 852 for literal/length codes and 594 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribtution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 32 6 15" for distance codes returns 594. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in infback9.c. If the root table size is changed, + then these maximum sizes would be need to be recalculated and updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 594 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table9() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +extern int inflate_table9 OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/test/zlib/zlib-1.2.8/contrib/inflate86/inffas86.c b/test/zlib/zlib-1.2.8/contrib/inflate86/inffas86.c new file mode 100644 index 000000000..7292f67b7 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/inflate86/inffas86.c @@ -0,0 +1,1157 @@ +/* inffas86.c is a hand tuned assembler version of + * + * inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Copyright (C) 2003 Chris Anderson + * Please use the copyright conditions above. + * + * Dec-29-2003 -- I added AMD64 inflate asm support. This version is also + * slightly quicker on x86 systems because, instead of using rep movsb to copy + * data, it uses rep movsw, which moves data in 2-byte chunks instead of single + * bytes. I've tested the AMD64 code on a Fedora Core 1 + the x86_64 updates + * from http://fedora.linux.duke.edu/fc1_x86_64 + * which is running on an Athlon 64 3000+ / Gigabyte GA-K8VT800M system with + * 1GB ram. The 64-bit version is about 4% faster than the 32-bit version, + * when decompressing mozilla-source-1.3.tar.gz. + * + * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from + * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at + * the moment. I have successfully compiled and tested this code with gcc2.96, + * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S + * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX + * enabled. I will attempt to merge the MMX code into this version. Newer + * versions of this and inffast.S can be found at + * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/ + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* Mark Adler's comments from inffast.c: */ + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + struct inffast_ar { +/* 64 32 x86 x86_64 */ +/* ar offset register */ +/* 0 0 */ void *esp; /* esp save */ +/* 8 4 */ void *ebp; /* ebp save */ +/* 16 8 */ unsigned char FAR *in; /* esi rsi local strm->next_in */ +/* 24 12 */ unsigned char FAR *last; /* r9 while in < last */ +/* 32 16 */ unsigned char FAR *out; /* edi rdi local strm->next_out */ +/* 40 20 */ unsigned char FAR *beg; /* inflate()'s init next_out */ +/* 48 24 */ unsigned char FAR *end; /* r10 while out < end */ +/* 56 28 */ unsigned char FAR *window;/* size of window, wsize!=0 */ +/* 64 32 */ code const FAR *lcode; /* ebp rbp local strm->lencode */ +/* 72 36 */ code const FAR *dcode; /* r11 local strm->distcode */ +/* 80 40 */ unsigned long hold; /* edx rdx local strm->hold */ +/* 88 44 */ unsigned bits; /* ebx rbx local strm->bits */ +/* 92 48 */ unsigned wsize; /* window size */ +/* 96 52 */ unsigned write; /* window write index */ +/*100 56 */ unsigned lmask; /* r12 mask for lcode */ +/*104 60 */ unsigned dmask; /* r13 mask for dcode */ +/*108 64 */ unsigned len; /* r14 match length */ +/*112 68 */ unsigned dist; /* r15 match distance */ +/*116 72 */ unsigned status; /* set when state chng*/ + } ar; + +#if defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 ) +#define PAD_AVAIL_IN 6 +#define PAD_AVAIL_OUT 258 +#else +#define PAD_AVAIL_IN 5 +#define PAD_AVAIL_OUT 257 +#endif + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + ar.in = strm->next_in; + ar.last = ar.in + (strm->avail_in - PAD_AVAIL_IN); + ar.out = strm->next_out; + ar.beg = ar.out - (start - strm->avail_out); + ar.end = ar.out + (strm->avail_out - PAD_AVAIL_OUT); + ar.wsize = state->wsize; + ar.write = state->wnext; + ar.window = state->window; + ar.hold = state->hold; + ar.bits = state->bits; + ar.lcode = state->lencode; + ar.dcode = state->distcode; + ar.lmask = (1U << state->lenbits) - 1; + ar.dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + + /* align in on 1/2 hold size boundary */ + while (((unsigned long)(void *)ar.in & (sizeof(ar.hold) / 2 - 1)) != 0) { + ar.hold += (unsigned long)*ar.in++ << ar.bits; + ar.bits += 8; + } + +#if defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 ) + __asm__ __volatile__ ( +" leaq %0, %%rax\n" +" movq %%rbp, 8(%%rax)\n" /* save regs rbp and rsp */ +" movq %%rsp, (%%rax)\n" +" movq %%rax, %%rsp\n" /* make rsp point to &ar */ +" movq 16(%%rsp), %%rsi\n" /* rsi = in */ +" movq 32(%%rsp), %%rdi\n" /* rdi = out */ +" movq 24(%%rsp), %%r9\n" /* r9 = last */ +" movq 48(%%rsp), %%r10\n" /* r10 = end */ +" movq 64(%%rsp), %%rbp\n" /* rbp = lcode */ +" movq 72(%%rsp), %%r11\n" /* r11 = dcode */ +" movq 80(%%rsp), %%rdx\n" /* rdx = hold */ +" movl 88(%%rsp), %%ebx\n" /* ebx = bits */ +" movl 100(%%rsp), %%r12d\n" /* r12d = lmask */ +" movl 104(%%rsp), %%r13d\n" /* r13d = dmask */ + /* r14d = len */ + /* r15d = dist */ +" cld\n" +" cmpq %%rdi, %%r10\n" +" je .L_one_time\n" /* if only one decode left */ +" cmpq %%rsi, %%r9\n" +" je .L_one_time\n" +" jmp .L_do_loop\n" + +".L_one_time:\n" +" movq %%r12, %%r8\n" /* r8 = lmask */ +" cmpb $32, %%bl\n" +" ja .L_get_length_code_one_time\n" + +" lodsl\n" /* eax = *(uint *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $32, %%bl\n" /* bits += 32 */ +" shlq %%cl, %%rax\n" +" orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */ +" jmp .L_get_length_code_one_time\n" + +".align 32,0x90\n" +".L_while_test:\n" +" cmpq %%rdi, %%r10\n" +" jbe .L_break_loop\n" +" cmpq %%rsi, %%r9\n" +" jbe .L_break_loop\n" + +".L_do_loop:\n" +" movq %%r12, %%r8\n" /* r8 = lmask */ +" cmpb $32, %%bl\n" +" ja .L_get_length_code\n" /* if (32 < bits) */ + +" lodsl\n" /* eax = *(uint *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $32, %%bl\n" /* bits += 32 */ +" shlq %%cl, %%rax\n" +" orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */ + +".L_get_length_code:\n" +" andq %%rdx, %%r8\n" /* r8 &= hold */ +" movl (%%rbp,%%r8,4), %%eax\n" /* eax = lcode[hold & lmask] */ + +" movb %%ah, %%cl\n" /* cl = this.bits */ +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrq %%cl, %%rdx\n" /* hold >>= this.bits */ + +" testb %%al, %%al\n" +" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */ + +" movq %%r12, %%r8\n" /* r8 = lmask */ +" shrl $16, %%eax\n" /* output this.val char */ +" stosb\n" + +".L_get_length_code_one_time:\n" +" andq %%rdx, %%r8\n" /* r8 &= hold */ +" movl (%%rbp,%%r8,4), %%eax\n" /* eax = lcode[hold & lmask] */ + +".L_dolen:\n" +" movb %%ah, %%cl\n" /* cl = this.bits */ +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrq %%cl, %%rdx\n" /* hold >>= this.bits */ + +" testb %%al, %%al\n" +" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */ + +" shrl $16, %%eax\n" /* output this.val char */ +" stosb\n" +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_test_for_length_base:\n" +" movl %%eax, %%r14d\n" /* len = this */ +" shrl $16, %%r14d\n" /* len = this.val */ +" movb %%al, %%cl\n" + +" testb $16, %%al\n" +" jz .L_test_for_second_level_length\n" /* if ((op & 16) == 0) 8% */ +" andb $15, %%cl\n" /* op &= 15 */ +" jz .L_decode_distance\n" /* if (!op) */ + +".L_add_bits_to_len:\n" +" subb %%cl, %%bl\n" +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" shrq %%cl, %%rdx\n" +" addl %%eax, %%r14d\n" /* len += hold & mask[op] */ + +".L_decode_distance:\n" +" movq %%r13, %%r8\n" /* r8 = dmask */ +" cmpb $32, %%bl\n" +" ja .L_get_distance_code\n" /* if (32 < bits) */ + +" lodsl\n" /* eax = *(uint *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $32, %%bl\n" /* bits += 32 */ +" shlq %%cl, %%rax\n" +" orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */ + +".L_get_distance_code:\n" +" andq %%rdx, %%r8\n" /* r8 &= hold */ +" movl (%%r11,%%r8,4), %%eax\n" /* eax = dcode[hold & dmask] */ + +".L_dodist:\n" +" movl %%eax, %%r15d\n" /* dist = this */ +" shrl $16, %%r15d\n" /* dist = this.val */ +" movb %%ah, %%cl\n" +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrq %%cl, %%rdx\n" /* hold >>= this.bits */ +" movb %%al, %%cl\n" /* cl = this.op */ + +" testb $16, %%al\n" /* if ((op & 16) == 0) */ +" jz .L_test_for_second_level_dist\n" +" andb $15, %%cl\n" /* op &= 15 */ +" jz .L_check_dist_one\n" + +".L_add_bits_to_dist:\n" +" subb %%cl, %%bl\n" +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" /* (1 << op) - 1 */ +" andl %%edx, %%eax\n" /* eax &= hold */ +" shrq %%cl, %%rdx\n" +" addl %%eax, %%r15d\n" /* dist += hold & ((1 << op) - 1) */ + +".L_check_window:\n" +" movq %%rsi, %%r8\n" /* save in so from can use it's reg */ +" movq %%rdi, %%rax\n" +" subq 40(%%rsp), %%rax\n" /* nbytes = out - beg */ + +" cmpl %%r15d, %%eax\n" +" jb .L_clip_window\n" /* if (dist > nbytes) 4.2% */ + +" movl %%r14d, %%ecx\n" /* ecx = len */ +" movq %%rdi, %%rsi\n" +" subq %%r15, %%rsi\n" /* from = out - dist */ + +" sarl %%ecx\n" +" jnc .L_copy_two\n" /* if len % 2 == 0 */ + +" rep movsw\n" +" movb (%%rsi), %%al\n" +" movb %%al, (%%rdi)\n" +" incq %%rdi\n" + +" movq %%r8, %%rsi\n" /* move in back to %rsi, toss from */ +" jmp .L_while_test\n" + +".L_copy_two:\n" +" rep movsw\n" +" movq %%r8, %%rsi\n" /* move in back to %rsi, toss from */ +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_check_dist_one:\n" +" cmpl $1, %%r15d\n" /* if dist 1, is a memset */ +" jne .L_check_window\n" +" cmpq %%rdi, 40(%%rsp)\n" /* if out == beg, outside window */ +" je .L_check_window\n" + +" movl %%r14d, %%ecx\n" /* ecx = len */ +" movb -1(%%rdi), %%al\n" +" movb %%al, %%ah\n" + +" sarl %%ecx\n" +" jnc .L_set_two\n" +" movb %%al, (%%rdi)\n" +" incq %%rdi\n" + +".L_set_two:\n" +" rep stosw\n" +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_test_for_second_level_length:\n" +" testb $64, %%al\n" +" jnz .L_test_for_end_of_block\n" /* if ((op & 64) != 0) */ + +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" addl %%r14d, %%eax\n" /* eax += len */ +" movl (%%rbp,%%rax,4), %%eax\n" /* eax = lcode[val+(hold&mask[op])]*/ +" jmp .L_dolen\n" + +".align 32,0x90\n" +".L_test_for_second_level_dist:\n" +" testb $64, %%al\n" +" jnz .L_invalid_distance_code\n" /* if ((op & 64) != 0) */ + +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" addl %%r15d, %%eax\n" /* eax += dist */ +" movl (%%r11,%%rax,4), %%eax\n" /* eax = dcode[val+(hold&mask[op])]*/ +" jmp .L_dodist\n" + +".align 32,0x90\n" +".L_clip_window:\n" +" movl %%eax, %%ecx\n" /* ecx = nbytes */ +" movl 92(%%rsp), %%eax\n" /* eax = wsize, prepare for dist cmp */ +" negl %%ecx\n" /* nbytes = -nbytes */ + +" cmpl %%r15d, %%eax\n" +" jb .L_invalid_distance_too_far\n" /* if (dist > wsize) */ + +" addl %%r15d, %%ecx\n" /* nbytes = dist - nbytes */ +" cmpl $0, 96(%%rsp)\n" +" jne .L_wrap_around_window\n" /* if (write != 0) */ + +" movq 56(%%rsp), %%rsi\n" /* from = window */ +" subl %%ecx, %%eax\n" /* eax -= nbytes */ +" addq %%rax, %%rsi\n" /* from += wsize - nbytes */ + +" movl %%r14d, %%eax\n" /* eax = len */ +" cmpl %%ecx, %%r14d\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* eax -= nbytes */ +" rep movsb\n" +" movq %%rdi, %%rsi\n" +" subq %%r15, %%rsi\n" /* from = &out[ -dist ] */ +" jmp .L_do_copy\n" + +".align 32,0x90\n" +".L_wrap_around_window:\n" +" movl 96(%%rsp), %%eax\n" /* eax = write */ +" cmpl %%eax, %%ecx\n" +" jbe .L_contiguous_in_window\n" /* if (write >= nbytes) */ + +" movl 92(%%rsp), %%esi\n" /* from = wsize */ +" addq 56(%%rsp), %%rsi\n" /* from += window */ +" addq %%rax, %%rsi\n" /* from += write */ +" subq %%rcx, %%rsi\n" /* from -= nbytes */ +" subl %%eax, %%ecx\n" /* nbytes -= write */ + +" movl %%r14d, %%eax\n" /* eax = len */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movq 56(%%rsp), %%rsi\n" /* from = window */ +" movl 96(%%rsp), %%ecx\n" /* nbytes = write */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movq %%rdi, %%rsi\n" +" subq %%r15, %%rsi\n" /* from = out - dist */ +" jmp .L_do_copy\n" + +".align 32,0x90\n" +".L_contiguous_in_window:\n" +" movq 56(%%rsp), %%rsi\n" /* rsi = window */ +" addq %%rax, %%rsi\n" +" subq %%rcx, %%rsi\n" /* from += write - nbytes */ + +" movl %%r14d, %%eax\n" /* eax = len */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movq %%rdi, %%rsi\n" +" subq %%r15, %%rsi\n" /* from = out - dist */ +" jmp .L_do_copy\n" /* if (nbytes >= len) */ + +".align 32,0x90\n" +".L_do_copy:\n" +" movl %%eax, %%ecx\n" /* ecx = len */ +" rep movsb\n" + +" movq %%r8, %%rsi\n" /* move in back to %esi, toss from */ +" jmp .L_while_test\n" + +".L_test_for_end_of_block:\n" +" testb $32, %%al\n" +" jz .L_invalid_literal_length_code\n" +" movl $1, 116(%%rsp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_literal_length_code:\n" +" movl $2, 116(%%rsp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_distance_code:\n" +" movl $3, 116(%%rsp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_distance_too_far:\n" +" movl $4, 116(%%rsp)\n" +" jmp .L_break_loop_with_status\n" + +".L_break_loop:\n" +" movl $0, 116(%%rsp)\n" + +".L_break_loop_with_status:\n" +/* put in, out, bits, and hold back into ar and pop esp */ +" movq %%rsi, 16(%%rsp)\n" /* in */ +" movq %%rdi, 32(%%rsp)\n" /* out */ +" movl %%ebx, 88(%%rsp)\n" /* bits */ +" movq %%rdx, 80(%%rsp)\n" /* hold */ +" movq (%%rsp), %%rax\n" /* restore rbp and rsp */ +" movq 8(%%rsp), %%rbp\n" +" movq %%rax, %%rsp\n" + : + : "m" (ar) + : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi", + "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" + ); +#elif ( defined( __GNUC__ ) || defined( __ICC ) ) && defined( __i386 ) + __asm__ __volatile__ ( +" leal %0, %%eax\n" +" movl %%esp, (%%eax)\n" /* save esp, ebp */ +" movl %%ebp, 4(%%eax)\n" +" movl %%eax, %%esp\n" +" movl 8(%%esp), %%esi\n" /* esi = in */ +" movl 16(%%esp), %%edi\n" /* edi = out */ +" movl 40(%%esp), %%edx\n" /* edx = hold */ +" movl 44(%%esp), %%ebx\n" /* ebx = bits */ +" movl 32(%%esp), %%ebp\n" /* ebp = lcode */ + +" cld\n" +" jmp .L_do_loop\n" + +".align 32,0x90\n" +".L_while_test:\n" +" cmpl %%edi, 24(%%esp)\n" /* out < end */ +" jbe .L_break_loop\n" +" cmpl %%esi, 12(%%esp)\n" /* in < last */ +" jbe .L_break_loop\n" + +".L_do_loop:\n" +" cmpb $15, %%bl\n" +" ja .L_get_length_code\n" /* if (15 < bits) */ + +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ + +".L_get_length_code:\n" +" movl 56(%%esp), %%eax\n" /* eax = lmask */ +" andl %%edx, %%eax\n" /* eax &= hold */ +" movl (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[hold & lmask] */ + +".L_dolen:\n" +" movb %%ah, %%cl\n" /* cl = this.bits */ +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrl %%cl, %%edx\n" /* hold >>= this.bits */ + +" testb %%al, %%al\n" +" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */ + +" shrl $16, %%eax\n" /* output this.val char */ +" stosb\n" +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_test_for_length_base:\n" +" movl %%eax, %%ecx\n" /* len = this */ +" shrl $16, %%ecx\n" /* len = this.val */ +" movl %%ecx, 64(%%esp)\n" /* save len */ +" movb %%al, %%cl\n" + +" testb $16, %%al\n" +" jz .L_test_for_second_level_length\n" /* if ((op & 16) == 0) 8% */ +" andb $15, %%cl\n" /* op &= 15 */ +" jz .L_decode_distance\n" /* if (!op) */ +" cmpb %%cl, %%bl\n" +" jae .L_add_bits_to_len\n" /* if (op <= bits) */ + +" movb %%cl, %%ch\n" /* stash op in ch, freeing cl */ +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ +" movb %%ch, %%cl\n" /* move op back to ecx */ + +".L_add_bits_to_len:\n" +" subb %%cl, %%bl\n" +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" shrl %%cl, %%edx\n" +" addl %%eax, 64(%%esp)\n" /* len += hold & mask[op] */ + +".L_decode_distance:\n" +" cmpb $15, %%bl\n" +" ja .L_get_distance_code\n" /* if (15 < bits) */ + +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ + +".L_get_distance_code:\n" +" movl 60(%%esp), %%eax\n" /* eax = dmask */ +" movl 36(%%esp), %%ecx\n" /* ecx = dcode */ +" andl %%edx, %%eax\n" /* eax &= hold */ +" movl (%%ecx,%%eax,4), %%eax\n"/* eax = dcode[hold & dmask] */ + +".L_dodist:\n" +" movl %%eax, %%ebp\n" /* dist = this */ +" shrl $16, %%ebp\n" /* dist = this.val */ +" movb %%ah, %%cl\n" +" subb %%ah, %%bl\n" /* bits -= this.bits */ +" shrl %%cl, %%edx\n" /* hold >>= this.bits */ +" movb %%al, %%cl\n" /* cl = this.op */ + +" testb $16, %%al\n" /* if ((op & 16) == 0) */ +" jz .L_test_for_second_level_dist\n" +" andb $15, %%cl\n" /* op &= 15 */ +" jz .L_check_dist_one\n" +" cmpb %%cl, %%bl\n" +" jae .L_add_bits_to_dist\n" /* if (op <= bits) 97.6% */ + +" movb %%cl, %%ch\n" /* stash op in ch, freeing cl */ +" xorl %%eax, %%eax\n" +" lodsw\n" /* al = *(ushort *)in++ */ +" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */ +" addb $16, %%bl\n" /* bits += 16 */ +" shll %%cl, %%eax\n" +" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */ +" movb %%ch, %%cl\n" /* move op back to ecx */ + +".L_add_bits_to_dist:\n" +" subb %%cl, %%bl\n" +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" /* (1 << op) - 1 */ +" andl %%edx, %%eax\n" /* eax &= hold */ +" shrl %%cl, %%edx\n" +" addl %%eax, %%ebp\n" /* dist += hold & ((1 << op) - 1) */ + +".L_check_window:\n" +" movl %%esi, 8(%%esp)\n" /* save in so from can use it's reg */ +" movl %%edi, %%eax\n" +" subl 20(%%esp), %%eax\n" /* nbytes = out - beg */ + +" cmpl %%ebp, %%eax\n" +" jb .L_clip_window\n" /* if (dist > nbytes) 4.2% */ + +" movl 64(%%esp), %%ecx\n" /* ecx = len */ +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ + +" sarl %%ecx\n" +" jnc .L_copy_two\n" /* if len % 2 == 0 */ + +" rep movsw\n" +" movb (%%esi), %%al\n" +" movb %%al, (%%edi)\n" +" incl %%edi\n" + +" movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */ +" movl 32(%%esp), %%ebp\n" /* ebp = lcode */ +" jmp .L_while_test\n" + +".L_copy_two:\n" +" rep movsw\n" +" movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */ +" movl 32(%%esp), %%ebp\n" /* ebp = lcode */ +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_check_dist_one:\n" +" cmpl $1, %%ebp\n" /* if dist 1, is a memset */ +" jne .L_check_window\n" +" cmpl %%edi, 20(%%esp)\n" +" je .L_check_window\n" /* out == beg, if outside window */ + +" movl 64(%%esp), %%ecx\n" /* ecx = len */ +" movb -1(%%edi), %%al\n" +" movb %%al, %%ah\n" + +" sarl %%ecx\n" +" jnc .L_set_two\n" +" movb %%al, (%%edi)\n" +" incl %%edi\n" + +".L_set_two:\n" +" rep stosw\n" +" movl 32(%%esp), %%ebp\n" /* ebp = lcode */ +" jmp .L_while_test\n" + +".align 32,0x90\n" +".L_test_for_second_level_length:\n" +" testb $64, %%al\n" +" jnz .L_test_for_end_of_block\n" /* if ((op & 64) != 0) */ + +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" addl 64(%%esp), %%eax\n" /* eax += len */ +" movl (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[val+(hold&mask[op])]*/ +" jmp .L_dolen\n" + +".align 32,0x90\n" +".L_test_for_second_level_dist:\n" +" testb $64, %%al\n" +" jnz .L_invalid_distance_code\n" /* if ((op & 64) != 0) */ + +" xorl %%eax, %%eax\n" +" incl %%eax\n" +" shll %%cl, %%eax\n" +" decl %%eax\n" +" andl %%edx, %%eax\n" /* eax &= hold */ +" addl %%ebp, %%eax\n" /* eax += dist */ +" movl 36(%%esp), %%ecx\n" /* ecx = dcode */ +" movl (%%ecx,%%eax,4), %%eax\n" /* eax = dcode[val+(hold&mask[op])]*/ +" jmp .L_dodist\n" + +".align 32,0x90\n" +".L_clip_window:\n" +" movl %%eax, %%ecx\n" +" movl 48(%%esp), %%eax\n" /* eax = wsize */ +" negl %%ecx\n" /* nbytes = -nbytes */ +" movl 28(%%esp), %%esi\n" /* from = window */ + +" cmpl %%ebp, %%eax\n" +" jb .L_invalid_distance_too_far\n" /* if (dist > wsize) */ + +" addl %%ebp, %%ecx\n" /* nbytes = dist - nbytes */ +" cmpl $0, 52(%%esp)\n" +" jne .L_wrap_around_window\n" /* if (write != 0) */ + +" subl %%ecx, %%eax\n" +" addl %%eax, %%esi\n" /* from += wsize - nbytes */ + +" movl 64(%%esp), %%eax\n" /* eax = len */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ +" jmp .L_do_copy\n" + +".align 32,0x90\n" +".L_wrap_around_window:\n" +" movl 52(%%esp), %%eax\n" /* eax = write */ +" cmpl %%eax, %%ecx\n" +" jbe .L_contiguous_in_window\n" /* if (write >= nbytes) */ + +" addl 48(%%esp), %%esi\n" /* from += wsize */ +" addl %%eax, %%esi\n" /* from += write */ +" subl %%ecx, %%esi\n" /* from -= nbytes */ +" subl %%eax, %%ecx\n" /* nbytes -= write */ + +" movl 64(%%esp), %%eax\n" /* eax = len */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl 28(%%esp), %%esi\n" /* from = window */ +" movl 52(%%esp), %%ecx\n" /* nbytes = write */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ +" jmp .L_do_copy\n" + +".align 32,0x90\n" +".L_contiguous_in_window:\n" +" addl %%eax, %%esi\n" +" subl %%ecx, %%esi\n" /* from += write - nbytes */ + +" movl 64(%%esp), %%eax\n" /* eax = len */ +" cmpl %%ecx, %%eax\n" +" jbe .L_do_copy\n" /* if (nbytes >= len) */ + +" subl %%ecx, %%eax\n" /* len -= nbytes */ +" rep movsb\n" +" movl %%edi, %%esi\n" +" subl %%ebp, %%esi\n" /* from = out - dist */ +" jmp .L_do_copy\n" /* if (nbytes >= len) */ + +".align 32,0x90\n" +".L_do_copy:\n" +" movl %%eax, %%ecx\n" +" rep movsb\n" + +" movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */ +" movl 32(%%esp), %%ebp\n" /* ebp = lcode */ +" jmp .L_while_test\n" + +".L_test_for_end_of_block:\n" +" testb $32, %%al\n" +" jz .L_invalid_literal_length_code\n" +" movl $1, 72(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_literal_length_code:\n" +" movl $2, 72(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_distance_code:\n" +" movl $3, 72(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_invalid_distance_too_far:\n" +" movl 8(%%esp), %%esi\n" +" movl $4, 72(%%esp)\n" +" jmp .L_break_loop_with_status\n" + +".L_break_loop:\n" +" movl $0, 72(%%esp)\n" + +".L_break_loop_with_status:\n" +/* put in, out, bits, and hold back into ar and pop esp */ +" movl %%esi, 8(%%esp)\n" /* save in */ +" movl %%edi, 16(%%esp)\n" /* save out */ +" movl %%ebx, 44(%%esp)\n" /* save bits */ +" movl %%edx, 40(%%esp)\n" /* save hold */ +" movl 4(%%esp), %%ebp\n" /* restore esp, ebp */ +" movl (%%esp), %%esp\n" + : + : "m" (ar) + : "memory", "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi" + ); +#elif defined( _MSC_VER ) && ! defined( _M_AMD64 ) + __asm { + lea eax, ar + mov [eax], esp /* save esp, ebp */ + mov [eax+4], ebp + mov esp, eax + mov esi, [esp+8] /* esi = in */ + mov edi, [esp+16] /* edi = out */ + mov edx, [esp+40] /* edx = hold */ + mov ebx, [esp+44] /* ebx = bits */ + mov ebp, [esp+32] /* ebp = lcode */ + + cld + jmp L_do_loop + +ALIGN 4 +L_while_test: + cmp [esp+24], edi + jbe L_break_loop + cmp [esp+12], esi + jbe L_break_loop + +L_do_loop: + cmp bl, 15 + ja L_get_length_code /* if (15 < bits) */ + + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + +L_get_length_code: + mov eax, [esp+56] /* eax = lmask */ + and eax, edx /* eax &= hold */ + mov eax, [ebp+eax*4] /* eax = lcode[hold & lmask] */ + +L_dolen: + mov cl, ah /* cl = this.bits */ + sub bl, ah /* bits -= this.bits */ + shr edx, cl /* hold >>= this.bits */ + + test al, al + jnz L_test_for_length_base /* if (op != 0) 45.7% */ + + shr eax, 16 /* output this.val char */ + stosb + jmp L_while_test + +ALIGN 4 +L_test_for_length_base: + mov ecx, eax /* len = this */ + shr ecx, 16 /* len = this.val */ + mov [esp+64], ecx /* save len */ + mov cl, al + + test al, 16 + jz L_test_for_second_level_length /* if ((op & 16) == 0) 8% */ + and cl, 15 /* op &= 15 */ + jz L_decode_distance /* if (!op) */ + cmp bl, cl + jae L_add_bits_to_len /* if (op <= bits) */ + + mov ch, cl /* stash op in ch, freeing cl */ + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + mov cl, ch /* move op back to ecx */ + +L_add_bits_to_len: + sub bl, cl + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx /* eax &= hold */ + shr edx, cl + add [esp+64], eax /* len += hold & mask[op] */ + +L_decode_distance: + cmp bl, 15 + ja L_get_distance_code /* if (15 < bits) */ + + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + +L_get_distance_code: + mov eax, [esp+60] /* eax = dmask */ + mov ecx, [esp+36] /* ecx = dcode */ + and eax, edx /* eax &= hold */ + mov eax, [ecx+eax*4]/* eax = dcode[hold & dmask] */ + +L_dodist: + mov ebp, eax /* dist = this */ + shr ebp, 16 /* dist = this.val */ + mov cl, ah + sub bl, ah /* bits -= this.bits */ + shr edx, cl /* hold >>= this.bits */ + mov cl, al /* cl = this.op */ + + test al, 16 /* if ((op & 16) == 0) */ + jz L_test_for_second_level_dist + and cl, 15 /* op &= 15 */ + jz L_check_dist_one + cmp bl, cl + jae L_add_bits_to_dist /* if (op <= bits) 97.6% */ + + mov ch, cl /* stash op in ch, freeing cl */ + xor eax, eax + lodsw /* al = *(ushort *)in++ */ + mov cl, bl /* cl = bits, needs it for shifting */ + add bl, 16 /* bits += 16 */ + shl eax, cl + or edx, eax /* hold |= *((ushort *)in)++ << bits */ + mov cl, ch /* move op back to ecx */ + +L_add_bits_to_dist: + sub bl, cl + xor eax, eax + inc eax + shl eax, cl + dec eax /* (1 << op) - 1 */ + and eax, edx /* eax &= hold */ + shr edx, cl + add ebp, eax /* dist += hold & ((1 << op) - 1) */ + +L_check_window: + mov [esp+8], esi /* save in so from can use it's reg */ + mov eax, edi + sub eax, [esp+20] /* nbytes = out - beg */ + + cmp eax, ebp + jb L_clip_window /* if (dist > nbytes) 4.2% */ + + mov ecx, [esp+64] /* ecx = len */ + mov esi, edi + sub esi, ebp /* from = out - dist */ + + sar ecx, 1 + jnc L_copy_two + + rep movsw + mov al, [esi] + mov [edi], al + inc edi + + mov esi, [esp+8] /* move in back to %esi, toss from */ + mov ebp, [esp+32] /* ebp = lcode */ + jmp L_while_test + +L_copy_two: + rep movsw + mov esi, [esp+8] /* move in back to %esi, toss from */ + mov ebp, [esp+32] /* ebp = lcode */ + jmp L_while_test + +ALIGN 4 +L_check_dist_one: + cmp ebp, 1 /* if dist 1, is a memset */ + jne L_check_window + cmp [esp+20], edi + je L_check_window /* out == beg, if outside window */ + + mov ecx, [esp+64] /* ecx = len */ + mov al, [edi-1] + mov ah, al + + sar ecx, 1 + jnc L_set_two + mov [edi], al /* memset out with from[-1] */ + inc edi + +L_set_two: + rep stosw + mov ebp, [esp+32] /* ebp = lcode */ + jmp L_while_test + +ALIGN 4 +L_test_for_second_level_length: + test al, 64 + jnz L_test_for_end_of_block /* if ((op & 64) != 0) */ + + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx /* eax &= hold */ + add eax, [esp+64] /* eax += len */ + mov eax, [ebp+eax*4] /* eax = lcode[val+(hold&mask[op])]*/ + jmp L_dolen + +ALIGN 4 +L_test_for_second_level_dist: + test al, 64 + jnz L_invalid_distance_code /* if ((op & 64) != 0) */ + + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx /* eax &= hold */ + add eax, ebp /* eax += dist */ + mov ecx, [esp+36] /* ecx = dcode */ + mov eax, [ecx+eax*4] /* eax = dcode[val+(hold&mask[op])]*/ + jmp L_dodist + +ALIGN 4 +L_clip_window: + mov ecx, eax + mov eax, [esp+48] /* eax = wsize */ + neg ecx /* nbytes = -nbytes */ + mov esi, [esp+28] /* from = window */ + + cmp eax, ebp + jb L_invalid_distance_too_far /* if (dist > wsize) */ + + add ecx, ebp /* nbytes = dist - nbytes */ + cmp dword ptr [esp+52], 0 + jne L_wrap_around_window /* if (write != 0) */ + + sub eax, ecx + add esi, eax /* from += wsize - nbytes */ + + mov eax, [esp+64] /* eax = len */ + cmp eax, ecx + jbe L_do_copy /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, edi + sub esi, ebp /* from = out - dist */ + jmp L_do_copy + +ALIGN 4 +L_wrap_around_window: + mov eax, [esp+52] /* eax = write */ + cmp ecx, eax + jbe L_contiguous_in_window /* if (write >= nbytes) */ + + add esi, [esp+48] /* from += wsize */ + add esi, eax /* from += write */ + sub esi, ecx /* from -= nbytes */ + sub ecx, eax /* nbytes -= write */ + + mov eax, [esp+64] /* eax = len */ + cmp eax, ecx + jbe L_do_copy /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, [esp+28] /* from = window */ + mov ecx, [esp+52] /* nbytes = write */ + cmp eax, ecx + jbe L_do_copy /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, edi + sub esi, ebp /* from = out - dist */ + jmp L_do_copy + +ALIGN 4 +L_contiguous_in_window: + add esi, eax + sub esi, ecx /* from += write - nbytes */ + + mov eax, [esp+64] /* eax = len */ + cmp eax, ecx + jbe L_do_copy /* if (nbytes >= len) */ + + sub eax, ecx /* len -= nbytes */ + rep movsb + mov esi, edi + sub esi, ebp /* from = out - dist */ + jmp L_do_copy + +ALIGN 4 +L_do_copy: + mov ecx, eax + rep movsb + + mov esi, [esp+8] /* move in back to %esi, toss from */ + mov ebp, [esp+32] /* ebp = lcode */ + jmp L_while_test + +L_test_for_end_of_block: + test al, 32 + jz L_invalid_literal_length_code + mov dword ptr [esp+72], 1 + jmp L_break_loop_with_status + +L_invalid_literal_length_code: + mov dword ptr [esp+72], 2 + jmp L_break_loop_with_status + +L_invalid_distance_code: + mov dword ptr [esp+72], 3 + jmp L_break_loop_with_status + +L_invalid_distance_too_far: + mov esi, [esp+4] + mov dword ptr [esp+72], 4 + jmp L_break_loop_with_status + +L_break_loop: + mov dword ptr [esp+72], 0 + +L_break_loop_with_status: +/* put in, out, bits, and hold back into ar and pop esp */ + mov [esp+8], esi /* save in */ + mov [esp+16], edi /* save out */ + mov [esp+44], ebx /* save bits */ + mov [esp+40], edx /* save hold */ + mov ebp, [esp+4] /* restore esp, ebp */ + mov esp, [esp] + } +#else +#error "x86 architecture not defined" +#endif + + if (ar.status > 1) { + if (ar.status == 2) + strm->msg = "invalid literal/length code"; + else if (ar.status == 3) + strm->msg = "invalid distance code"; + else + strm->msg = "invalid distance too far back"; + state->mode = BAD; + } + else if ( ar.status == 1 ) { + state->mode = TYPE; + } + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + ar.len = ar.bits >> 3; + ar.in -= ar.len; + ar.bits -= ar.len << 3; + ar.hold &= (1U << ar.bits) - 1; + + /* update state and return */ + strm->next_in = ar.in; + strm->next_out = ar.out; + strm->avail_in = (unsigned)(ar.in < ar.last ? + PAD_AVAIL_IN + (ar.last - ar.in) : + PAD_AVAIL_IN - (ar.in - ar.last)); + strm->avail_out = (unsigned)(ar.out < ar.end ? + PAD_AVAIL_OUT + (ar.end - ar.out) : + PAD_AVAIL_OUT - (ar.out - ar.end)); + state->hold = ar.hold; + state->bits = ar.bits; + return; +} + diff --git a/test/zlib/zlib-1.2.8/contrib/inflate86/inffast.S b/test/zlib/zlib-1.2.8/contrib/inflate86/inffast.S new file mode 100644 index 000000000..2245a2905 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/inflate86/inffast.S @@ -0,0 +1,1368 @@ +/* + * inffast.S is a hand tuned assembler version of: + * + * inffast.c -- fast decoding + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Copyright (C) 2003 Chris Anderson + * Please use the copyright conditions above. + * + * This version (Jan-23-2003) of inflate_fast was coded and tested under + * GNU/Linux on a pentium 3, using the gcc-3.2 compiler distribution. On that + * machine, I found that gzip style archives decompressed about 20% faster than + * the gcc-3.2 -O3 -fomit-frame-pointer compiled version. Your results will + * depend on how large of a buffer is used for z_stream.next_in & next_out + * (8K-32K worked best for my 256K cpu cache) and how much overhead there is in + * stream processing I/O and crc32/addler32. In my case, this routine used + * 70% of the cpu time and crc32 used 20%. + * + * I am confident that this version will work in the general case, but I have + * not tested a wide variety of datasets or a wide variety of platforms. + * + * Jan-24-2003 -- Added -DUSE_MMX define for slightly faster inflating. + * It should be a runtime flag instead of compile time flag... + * + * Jan-26-2003 -- Added runtime check for MMX support with cpuid instruction. + * With -DUSE_MMX, only MMX code is compiled. With -DNO_MMX, only non-MMX code + * is compiled. Without either option, runtime detection is enabled. Runtime + * detection should work on all modern cpus and the recomended algorithm (flip + * ID bit on eflags and then use the cpuid instruction) is used in many + * multimedia applications. Tested under win2k with gcc-2.95 and gas-2.12 + * distributed with cygwin3. Compiling with gcc-2.95 -c inffast.S -o + * inffast.obj generates a COFF object which can then be linked with MSVC++ + * compiled code. Tested under FreeBSD 4.7 with gcc-2.95. + * + * Jan-28-2003 -- Tested Athlon XP... MMX mode is slower than no MMX (and + * slower than compiler generated code). Adjusted cpuid check to use the MMX + * code only for Pentiums < P4 until I have more data on the P4. Speed + * improvment is only about 15% on the Athlon when compared with code generated + * with MSVC++. Not sure yet, but I think the P4 will also be slower using the + * MMX mode because many of it's x86 ALU instructions execute in .5 cycles and + * have less latency than MMX ops. Added code to buffer the last 11 bytes of + * the input stream since the MMX code grabs bits in chunks of 32, which + * differs from the inffast.c algorithm. I don't think there would have been + * read overruns where a page boundary was crossed (a segfault), but there + * could have been overruns when next_in ends on unaligned memory (unintialized + * memory read). + * + * Mar-13-2003 -- P4 MMX is slightly slower than P4 NO_MMX. I created a C + * version of the non-MMX code so that it doesn't depend on zstrm and zstate + * structure offsets which are hard coded in this file. This was last tested + * with zlib-1.2.0 which is currently in beta testing, newer versions of this + * and inffas86.c can be found at http://www.eetbeetee.com/zlib/ and + * http://www.charm.net/~christop/zlib/ + */ + + +/* + * if you have underscore linking problems (_inflate_fast undefined), try + * using -DGAS_COFF + */ +#if ! defined( GAS_COFF ) && ! defined( GAS_ELF ) + +#if defined( WIN32 ) || defined( __CYGWIN__ ) +#define GAS_COFF /* windows object format */ +#else +#define GAS_ELF +#endif + +#endif /* ! GAS_COFF && ! GAS_ELF */ + + +#if defined( GAS_COFF ) + +/* coff externals have underscores */ +#define inflate_fast _inflate_fast +#define inflate_fast_use_mmx _inflate_fast_use_mmx + +#endif /* GAS_COFF */ + + +.file "inffast.S" + +.globl inflate_fast + +.text +.align 4,0 +.L_invalid_literal_length_code_msg: +.string "invalid literal/length code" + +.align 4,0 +.L_invalid_distance_code_msg: +.string "invalid distance code" + +.align 4,0 +.L_invalid_distance_too_far_msg: +.string "invalid distance too far back" + +#if ! defined( NO_MMX ) +.align 4,0 +.L_mask: /* mask[N] = ( 1 << N ) - 1 */ +.long 0 +.long 1 +.long 3 +.long 7 +.long 15 +.long 31 +.long 63 +.long 127 +.long 255 +.long 511 +.long 1023 +.long 2047 +.long 4095 +.long 8191 +.long 16383 +.long 32767 +.long 65535 +.long 131071 +.long 262143 +.long 524287 +.long 1048575 +.long 2097151 +.long 4194303 +.long 8388607 +.long 16777215 +.long 33554431 +.long 67108863 +.long 134217727 +.long 268435455 +.long 536870911 +.long 1073741823 +.long 2147483647 +.long 4294967295 +#endif /* NO_MMX */ + +.text + +/* + * struct z_stream offsets, in zlib.h + */ +#define next_in_strm 0 /* strm->next_in */ +#define avail_in_strm 4 /* strm->avail_in */ +#define next_out_strm 12 /* strm->next_out */ +#define avail_out_strm 16 /* strm->avail_out */ +#define msg_strm 24 /* strm->msg */ +#define state_strm 28 /* strm->state */ + +/* + * struct inflate_state offsets, in inflate.h + */ +#define mode_state 0 /* state->mode */ +#define wsize_state 32 /* state->wsize */ +#define write_state 40 /* state->write */ +#define window_state 44 /* state->window */ +#define hold_state 48 /* state->hold */ +#define bits_state 52 /* state->bits */ +#define lencode_state 68 /* state->lencode */ +#define distcode_state 72 /* state->distcode */ +#define lenbits_state 76 /* state->lenbits */ +#define distbits_state 80 /* state->distbits */ + +/* + * inflate_fast's activation record + */ +#define local_var_size 64 /* how much local space for vars */ +#define strm_sp 88 /* first arg: z_stream * (local_var_size + 24) */ +#define start_sp 92 /* second arg: unsigned int (local_var_size + 28) */ + +/* + * offsets for local vars on stack + */ +#define out 60 /* unsigned char* */ +#define window 56 /* unsigned char* */ +#define wsize 52 /* unsigned int */ +#define write 48 /* unsigned int */ +#define in 44 /* unsigned char* */ +#define beg 40 /* unsigned char* */ +#define buf 28 /* char[ 12 ] */ +#define len 24 /* unsigned int */ +#define last 20 /* unsigned char* */ +#define end 16 /* unsigned char* */ +#define dcode 12 /* code* */ +#define lcode 8 /* code* */ +#define dmask 4 /* unsigned int */ +#define lmask 0 /* unsigned int */ + +/* + * typedef enum inflate_mode consts, in inflate.h + */ +#define INFLATE_MODE_TYPE 11 /* state->mode flags enum-ed in inflate.h */ +#define INFLATE_MODE_BAD 26 + + +#if ! defined( USE_MMX ) && ! defined( NO_MMX ) + +#define RUN_TIME_MMX + +#define CHECK_MMX 1 +#define DO_USE_MMX 2 +#define DONT_USE_MMX 3 + +.globl inflate_fast_use_mmx + +.data + +.align 4,0 +inflate_fast_use_mmx: /* integer flag for run time control 1=check,2=mmx,3=no */ +.long CHECK_MMX + +#if defined( GAS_ELF ) +/* elf info */ +.type inflate_fast_use_mmx,@object +.size inflate_fast_use_mmx,4 +#endif + +#endif /* RUN_TIME_MMX */ + +#if defined( GAS_COFF ) +/* coff info: scl 2 = extern, type 32 = function */ +.def inflate_fast; .scl 2; .type 32; .endef +#endif + +.text + +.align 32,0x90 +inflate_fast: + pushl %edi + pushl %esi + pushl %ebp + pushl %ebx + pushf /* save eflags (strm_sp, state_sp assumes this is 32 bits) */ + subl $local_var_size, %esp + cld + +#define strm_r %esi +#define state_r %edi + + movl strm_sp(%esp), strm_r + movl state_strm(strm_r), state_r + + /* in = strm->next_in; + * out = strm->next_out; + * last = in + strm->avail_in - 11; + * beg = out - (start - strm->avail_out); + * end = out + (strm->avail_out - 257); + */ + movl avail_in_strm(strm_r), %edx + movl next_in_strm(strm_r), %eax + + addl %eax, %edx /* avail_in += next_in */ + subl $11, %edx /* avail_in -= 11 */ + + movl %eax, in(%esp) + movl %edx, last(%esp) + + movl start_sp(%esp), %ebp + movl avail_out_strm(strm_r), %ecx + movl next_out_strm(strm_r), %ebx + + subl %ecx, %ebp /* start -= avail_out */ + negl %ebp /* start = -start */ + addl %ebx, %ebp /* start += next_out */ + + subl $257, %ecx /* avail_out -= 257 */ + addl %ebx, %ecx /* avail_out += out */ + + movl %ebx, out(%esp) + movl %ebp, beg(%esp) + movl %ecx, end(%esp) + + /* wsize = state->wsize; + * write = state->write; + * window = state->window; + * hold = state->hold; + * bits = state->bits; + * lcode = state->lencode; + * dcode = state->distcode; + * lmask = ( 1 << state->lenbits ) - 1; + * dmask = ( 1 << state->distbits ) - 1; + */ + + movl lencode_state(state_r), %eax + movl distcode_state(state_r), %ecx + + movl %eax, lcode(%esp) + movl %ecx, dcode(%esp) + + movl $1, %eax + movl lenbits_state(state_r), %ecx + shll %cl, %eax + decl %eax + movl %eax, lmask(%esp) + + movl $1, %eax + movl distbits_state(state_r), %ecx + shll %cl, %eax + decl %eax + movl %eax, dmask(%esp) + + movl wsize_state(state_r), %eax + movl write_state(state_r), %ecx + movl window_state(state_r), %edx + + movl %eax, wsize(%esp) + movl %ecx, write(%esp) + movl %edx, window(%esp) + + movl hold_state(state_r), %ebp + movl bits_state(state_r), %ebx + +#undef strm_r +#undef state_r + +#define in_r %esi +#define from_r %esi +#define out_r %edi + + movl in(%esp), in_r + movl last(%esp), %ecx + cmpl in_r, %ecx + ja .L_align_long /* if in < last */ + + addl $11, %ecx /* ecx = &in[ avail_in ] */ + subl in_r, %ecx /* ecx = avail_in */ + movl $12, %eax + subl %ecx, %eax /* eax = 12 - avail_in */ + leal buf(%esp), %edi + rep movsb /* memcpy( buf, in, avail_in ) */ + movl %eax, %ecx + xorl %eax, %eax + rep stosb /* memset( &buf[ avail_in ], 0, 12 - avail_in ) */ + leal buf(%esp), in_r /* in = buf */ + movl in_r, last(%esp) /* last = in, do just one iteration */ + jmp .L_is_aligned + + /* align in_r on long boundary */ +.L_align_long: + testl $3, in_r + jz .L_is_aligned + xorl %eax, %eax + movb (in_r), %al + incl in_r + movl %ebx, %ecx + addl $8, %ebx + shll %cl, %eax + orl %eax, %ebp + jmp .L_align_long + +.L_is_aligned: + movl out(%esp), out_r + +#if defined( NO_MMX ) + jmp .L_do_loop +#endif + +#if defined( USE_MMX ) + jmp .L_init_mmx +#endif + +/*** Runtime MMX check ***/ + +#if defined( RUN_TIME_MMX ) +.L_check_mmx: + cmpl $DO_USE_MMX, inflate_fast_use_mmx + je .L_init_mmx + ja .L_do_loop /* > 2 */ + + pushl %eax + pushl %ebx + pushl %ecx + pushl %edx + pushf + movl (%esp), %eax /* copy eflags to eax */ + xorl $0x200000, (%esp) /* try toggling ID bit of eflags (bit 21) + * to see if cpu supports cpuid... + * ID bit method not supported by NexGen but + * bios may load a cpuid instruction and + * cpuid may be disabled on Cyrix 5-6x86 */ + popf + pushf + popl %edx /* copy new eflags to edx */ + xorl %eax, %edx /* test if ID bit is flipped */ + jz .L_dont_use_mmx /* not flipped if zero */ + xorl %eax, %eax + cpuid + cmpl $0x756e6547, %ebx /* check for GenuineIntel in ebx,ecx,edx */ + jne .L_dont_use_mmx + cmpl $0x6c65746e, %ecx + jne .L_dont_use_mmx + cmpl $0x49656e69, %edx + jne .L_dont_use_mmx + movl $1, %eax + cpuid /* get cpu features */ + shrl $8, %eax + andl $15, %eax + cmpl $6, %eax /* check for Pentium family, is 0xf for P4 */ + jne .L_dont_use_mmx + testl $0x800000, %edx /* test if MMX feature is set (bit 23) */ + jnz .L_use_mmx + jmp .L_dont_use_mmx +.L_use_mmx: + movl $DO_USE_MMX, inflate_fast_use_mmx + jmp .L_check_mmx_pop +.L_dont_use_mmx: + movl $DONT_USE_MMX, inflate_fast_use_mmx +.L_check_mmx_pop: + popl %edx + popl %ecx + popl %ebx + popl %eax + jmp .L_check_mmx +#endif + + +/*** Non-MMX code ***/ + +#if defined ( NO_MMX ) || defined( RUN_TIME_MMX ) + +#define hold_r %ebp +#define bits_r %bl +#define bitslong_r %ebx + +.align 32,0x90 +.L_while_test: + /* while (in < last && out < end) + */ + cmpl out_r, end(%esp) + jbe .L_break_loop /* if (out >= end) */ + + cmpl in_r, last(%esp) + jbe .L_break_loop + +.L_do_loop: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out + * + * do { + * if (bits < 15) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * this = lcode[hold & lmask] + */ + cmpb $15, bits_r + ja .L_get_length_code /* if (15 < bits) */ + + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + +.L_get_length_code: + movl lmask(%esp), %edx /* edx = lmask */ + movl lcode(%esp), %ecx /* ecx = lcode */ + andl hold_r, %edx /* edx &= hold */ + movl (%ecx,%edx,4), %eax /* eax = lcode[hold & lmask] */ + +.L_dolen: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out + * + * dolen: + * bits -= this.bits; + * hold >>= this.bits + */ + movb %ah, %cl /* cl = this.bits */ + subb %ah, bits_r /* bits -= this.bits */ + shrl %cl, hold_r /* hold >>= this.bits */ + + /* check if op is a literal + * if (op == 0) { + * PUP(out) = this.val; + * } + */ + testb %al, %al + jnz .L_test_for_length_base /* if (op != 0) 45.7% */ + + shrl $16, %eax /* output this.val char */ + stosb + jmp .L_while_test + +.L_test_for_length_base: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = len + * + * else if (op & 16) { + * len = this.val + * op &= 15 + * if (op) { + * if (op > bits) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * len += hold & mask[op]; + * bits -= op; + * hold >>= op; + * } + */ +#define len_r %edx + movl %eax, len_r /* len = this */ + shrl $16, len_r /* len = this.val */ + movb %al, %cl + + testb $16, %al + jz .L_test_for_second_level_length /* if ((op & 16) == 0) 8% */ + andb $15, %cl /* op &= 15 */ + jz .L_save_len /* if (!op) */ + cmpb %cl, bits_r + jae .L_add_bits_to_len /* if (op <= bits) */ + + movb %cl, %ch /* stash op in ch, freeing cl */ + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + movb %ch, %cl /* move op back to ecx */ + +.L_add_bits_to_len: + movl $1, %eax + shll %cl, %eax + decl %eax + subb %cl, bits_r + andl hold_r, %eax /* eax &= hold */ + shrl %cl, hold_r + addl %eax, len_r /* len += hold & mask[op] */ + +.L_save_len: + movl len_r, len(%esp) /* save len */ +#undef len_r + +.L_decode_distance: + /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * + * if (bits < 15) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * this = dcode[hold & dmask]; + * dodist: + * bits -= this.bits; + * hold >>= this.bits; + * op = this.op; + */ + + cmpb $15, bits_r + ja .L_get_distance_code /* if (15 < bits) */ + + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + +.L_get_distance_code: + movl dmask(%esp), %edx /* edx = dmask */ + movl dcode(%esp), %ecx /* ecx = dcode */ + andl hold_r, %edx /* edx &= hold */ + movl (%ecx,%edx,4), %eax /* eax = dcode[hold & dmask] */ + +#define dist_r %edx +.L_dodist: + movl %eax, dist_r /* dist = this */ + shrl $16, dist_r /* dist = this.val */ + movb %ah, %cl + subb %ah, bits_r /* bits -= this.bits */ + shrl %cl, hold_r /* hold >>= this.bits */ + + /* if (op & 16) { + * dist = this.val + * op &= 15 + * if (op > bits) { + * hold |= *((unsigned short *)in)++ << bits; + * bits += 16 + * } + * dist += hold & mask[op]; + * bits -= op; + * hold >>= op; + */ + movb %al, %cl /* cl = this.op */ + + testb $16, %al /* if ((op & 16) == 0) */ + jz .L_test_for_second_level_dist + andb $15, %cl /* op &= 15 */ + jz .L_check_dist_one + cmpb %cl, bits_r + jae .L_add_bits_to_dist /* if (op <= bits) 97.6% */ + + movb %cl, %ch /* stash op in ch, freeing cl */ + xorl %eax, %eax + lodsw /* al = *(ushort *)in++ */ + movb bits_r, %cl /* cl = bits, needs it for shifting */ + addb $16, bits_r /* bits += 16 */ + shll %cl, %eax + orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */ + movb %ch, %cl /* move op back to ecx */ + +.L_add_bits_to_dist: + movl $1, %eax + shll %cl, %eax + decl %eax /* (1 << op) - 1 */ + subb %cl, bits_r + andl hold_r, %eax /* eax &= hold */ + shrl %cl, hold_r + addl %eax, dist_r /* dist += hold & ((1 << op) - 1) */ + jmp .L_check_window + +.L_check_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes + * + * nbytes = out - beg; + * if (dist <= nbytes) { + * from = out - dist; + * do { + * PUP(out) = PUP(from); + * } while (--len > 0) { + * } + */ + + movl in_r, in(%esp) /* save in so from can use it's reg */ + movl out_r, %eax + subl beg(%esp), %eax /* nbytes = out - beg */ + + cmpl dist_r, %eax + jb .L_clip_window /* if (dist > nbytes) 4.2% */ + + movl len(%esp), %ecx + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + + subl $3, %ecx + movb (from_r), %al + movb %al, (out_r) + movb 1(from_r), %al + movb 2(from_r), %dl + addl $3, from_r + movb %al, 1(out_r) + movb %dl, 2(out_r) + addl $3, out_r + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + jmp .L_while_test + +.align 16,0x90 +.L_check_dist_one: + cmpl $1, dist_r + jne .L_check_window + cmpl out_r, beg(%esp) + je .L_check_window + + decl out_r + movl len(%esp), %ecx + movb (out_r), %al + subl $3, %ecx + + movb %al, 1(out_r) + movb %al, 2(out_r) + movb %al, 3(out_r) + addl $4, out_r + rep stosb + + jmp .L_while_test + +.align 16,0x90 +.L_test_for_second_level_length: + /* else if ((op & 64) == 0) { + * this = lcode[this.val + (hold & mask[op])]; + * } + */ + testb $64, %al + jnz .L_test_for_end_of_block /* if ((op & 64) != 0) */ + + movl $1, %eax + shll %cl, %eax + decl %eax + andl hold_r, %eax /* eax &= hold */ + addl %edx, %eax /* eax += this.val */ + movl lcode(%esp), %edx /* edx = lcode */ + movl (%edx,%eax,4), %eax /* eax = lcode[val + (hold&mask[op])] */ + jmp .L_dolen + +.align 16,0x90 +.L_test_for_second_level_dist: + /* else if ((op & 64) == 0) { + * this = dcode[this.val + (hold & mask[op])]; + * } + */ + testb $64, %al + jnz .L_invalid_distance_code /* if ((op & 64) != 0) */ + + movl $1, %eax + shll %cl, %eax + decl %eax + andl hold_r, %eax /* eax &= hold */ + addl %edx, %eax /* eax += this.val */ + movl dcode(%esp), %edx /* edx = dcode */ + movl (%edx,%eax,4), %eax /* eax = dcode[val + (hold&mask[op])] */ + jmp .L_dodist + +.align 16,0x90 +.L_clip_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes + * + * else { + * if (dist > wsize) { + * invalid distance + * } + * from = window; + * nbytes = dist - nbytes; + * if (write == 0) { + * from += wsize - nbytes; + */ +#define nbytes_r %ecx + movl %eax, nbytes_r + movl wsize(%esp), %eax /* prepare for dist compare */ + negl nbytes_r /* nbytes = -nbytes */ + movl window(%esp), from_r /* from = window */ + + cmpl dist_r, %eax + jb .L_invalid_distance_too_far /* if (dist > wsize) */ + + addl dist_r, nbytes_r /* nbytes = dist - nbytes */ + cmpl $0, write(%esp) + jne .L_wrap_around_window /* if (write != 0) */ + + subl nbytes_r, %eax + addl %eax, from_r /* from += wsize - nbytes */ + + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes, %eax = len + * + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while (--nbytes); + * from = out - dist; + * } + * } + */ +#define len_r %eax + movl len(%esp), len_r + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1 + + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1 + +.L_wrap_around_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes, %eax = write, %eax = len + * + * else if (write < nbytes) { + * from += wsize + write - nbytes; + * nbytes -= write; + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while (--nbytes); + * from = window; + * nbytes = write; + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while(--nbytes); + * from = out - dist; + * } + * } + * } + */ +#define write_r %eax + movl write(%esp), write_r + cmpl write_r, nbytes_r + jbe .L_contiguous_in_window /* if (write >= nbytes) */ + + addl wsize(%esp), from_r + addl write_r, from_r + subl nbytes_r, from_r /* from += wsize + write - nbytes */ + subl write_r, nbytes_r /* nbytes -= write */ +#undef write_r + + movl len(%esp), len_r + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl window(%esp), from_r /* from = window */ + movl write(%esp), nbytes_r /* nbytes = write */ + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1 + +.L_contiguous_in_window: + /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist + * %ecx = nbytes, %eax = write, %eax = len + * + * else { + * from += write - nbytes; + * if (nbytes < len) { + * len -= nbytes; + * do { + * PUP(out) = PUP(from); + * } while (--nbytes); + * from = out - dist; + * } + * } + */ +#define write_r %eax + addl write_r, from_r + subl nbytes_r, from_r /* from += write - nbytes */ +#undef write_r + + movl len(%esp), len_r + cmpl nbytes_r, len_r + jbe .L_do_copy1 /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + +.L_do_copy1: + /* regs: %esi = from, %esi = in, %ebp = hold, %bl = bits, %edi = out + * %eax = len + * + * while (len > 0) { + * PUP(out) = PUP(from); + * len--; + * } + * } + * } while (in < last && out < end); + */ +#undef nbytes_r +#define in_r %esi + movl len_r, %ecx + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + jmp .L_while_test + +#undef len_r +#undef dist_r + +#endif /* NO_MMX || RUN_TIME_MMX */ + + +/*** MMX code ***/ + +#if defined( USE_MMX ) || defined( RUN_TIME_MMX ) + +.align 32,0x90 +.L_init_mmx: + emms + +#undef bits_r +#undef bitslong_r +#define bitslong_r %ebp +#define hold_mm %mm0 + movd %ebp, hold_mm + movl %ebx, bitslong_r + +#define used_mm %mm1 +#define dmask2_mm %mm2 +#define lmask2_mm %mm3 +#define lmask_mm %mm4 +#define dmask_mm %mm5 +#define tmp_mm %mm6 + + movd lmask(%esp), lmask_mm + movq lmask_mm, lmask2_mm + movd dmask(%esp), dmask_mm + movq dmask_mm, dmask2_mm + pxor used_mm, used_mm + movl lcode(%esp), %ebx /* ebx = lcode */ + jmp .L_do_loop_mmx + +.align 32,0x90 +.L_while_test_mmx: + /* while (in < last && out < end) + */ + cmpl out_r, end(%esp) + jbe .L_break_loop /* if (out >= end) */ + + cmpl in_r, last(%esp) + jbe .L_break_loop + +.L_do_loop_mmx: + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + + cmpl $32, bitslong_r + ja .L_get_length_code_mmx /* if (32 < bits) */ + + movd bitslong_r, tmp_mm + movd (in_r), %mm7 + addl $4, in_r + psllq tmp_mm, %mm7 + addl $32, bitslong_r + por %mm7, hold_mm /* hold_mm |= *((uint *)in)++ << bits */ + +.L_get_length_code_mmx: + pand hold_mm, lmask_mm + movd lmask_mm, %eax + movq lmask2_mm, lmask_mm + movl (%ebx,%eax,4), %eax /* eax = lcode[hold & lmask] */ + +.L_dolen_mmx: + movzbl %ah, %ecx /* ecx = this.bits */ + movd %ecx, used_mm + subl %ecx, bitslong_r /* bits -= this.bits */ + + testb %al, %al + jnz .L_test_for_length_base_mmx /* if (op != 0) 45.7% */ + + shrl $16, %eax /* output this.val char */ + stosb + jmp .L_while_test_mmx + +.L_test_for_length_base_mmx: +#define len_r %edx + movl %eax, len_r /* len = this */ + shrl $16, len_r /* len = this.val */ + + testb $16, %al + jz .L_test_for_second_level_length_mmx /* if ((op & 16) == 0) 8% */ + andl $15, %eax /* op &= 15 */ + jz .L_decode_distance_mmx /* if (!op) */ + + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd %eax, used_mm + movd hold_mm, %ecx + subl %eax, bitslong_r + andl .L_mask(,%eax,4), %ecx + addl %ecx, len_r /* len += hold & mask[op] */ + +.L_decode_distance_mmx: + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + + cmpl $32, bitslong_r + ja .L_get_dist_code_mmx /* if (32 < bits) */ + + movd bitslong_r, tmp_mm + movd (in_r), %mm7 + addl $4, in_r + psllq tmp_mm, %mm7 + addl $32, bitslong_r + por %mm7, hold_mm /* hold_mm |= *((uint *)in)++ << bits */ + +.L_get_dist_code_mmx: + movl dcode(%esp), %ebx /* ebx = dcode */ + pand hold_mm, dmask_mm + movd dmask_mm, %eax + movq dmask2_mm, dmask_mm + movl (%ebx,%eax,4), %eax /* eax = dcode[hold & lmask] */ + +.L_dodist_mmx: +#define dist_r %ebx + movzbl %ah, %ecx /* ecx = this.bits */ + movl %eax, dist_r + shrl $16, dist_r /* dist = this.val */ + subl %ecx, bitslong_r /* bits -= this.bits */ + movd %ecx, used_mm + + testb $16, %al /* if ((op & 16) == 0) */ + jz .L_test_for_second_level_dist_mmx + andl $15, %eax /* op &= 15 */ + jz .L_check_dist_one_mmx + +.L_add_bits_to_dist_mmx: + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd %eax, used_mm /* save bit length of current op */ + movd hold_mm, %ecx /* get the next bits on input stream */ + subl %eax, bitslong_r /* bits -= op bits */ + andl .L_mask(,%eax,4), %ecx /* ecx = hold & mask[op] */ + addl %ecx, dist_r /* dist += hold & mask[op] */ + +.L_check_window_mmx: + movl in_r, in(%esp) /* save in so from can use it's reg */ + movl out_r, %eax + subl beg(%esp), %eax /* nbytes = out - beg */ + + cmpl dist_r, %eax + jb .L_clip_window_mmx /* if (dist > nbytes) 4.2% */ + + movl len_r, %ecx + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + + subl $3, %ecx + movb (from_r), %al + movb %al, (out_r) + movb 1(from_r), %al + movb 2(from_r), %dl + addl $3, from_r + movb %al, 1(out_r) + movb %dl, 2(out_r) + addl $3, out_r + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */ + jmp .L_while_test_mmx + +.align 16,0x90 +.L_check_dist_one_mmx: + cmpl $1, dist_r + jne .L_check_window_mmx + cmpl out_r, beg(%esp) + je .L_check_window_mmx + + decl out_r + movl len_r, %ecx + movb (out_r), %al + subl $3, %ecx + + movb %al, 1(out_r) + movb %al, 2(out_r) + movb %al, 3(out_r) + addl $4, out_r + rep stosb + + movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */ + jmp .L_while_test_mmx + +.align 16,0x90 +.L_test_for_second_level_length_mmx: + testb $64, %al + jnz .L_test_for_end_of_block /* if ((op & 64) != 0) */ + + andl $15, %eax + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd hold_mm, %ecx + andl .L_mask(,%eax,4), %ecx + addl len_r, %ecx + movl (%ebx,%ecx,4), %eax /* eax = lcode[hold & lmask] */ + jmp .L_dolen_mmx + +.align 16,0x90 +.L_test_for_second_level_dist_mmx: + testb $64, %al + jnz .L_invalid_distance_code /* if ((op & 64) != 0) */ + + andl $15, %eax + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd hold_mm, %ecx + andl .L_mask(,%eax,4), %ecx + movl dcode(%esp), %eax /* ecx = dcode */ + addl dist_r, %ecx + movl (%eax,%ecx,4), %eax /* eax = lcode[hold & lmask] */ + jmp .L_dodist_mmx + +.align 16,0x90 +.L_clip_window_mmx: +#define nbytes_r %ecx + movl %eax, nbytes_r + movl wsize(%esp), %eax /* prepare for dist compare */ + negl nbytes_r /* nbytes = -nbytes */ + movl window(%esp), from_r /* from = window */ + + cmpl dist_r, %eax + jb .L_invalid_distance_too_far /* if (dist > wsize) */ + + addl dist_r, nbytes_r /* nbytes = dist - nbytes */ + cmpl $0, write(%esp) + jne .L_wrap_around_window_mmx /* if (write != 0) */ + + subl nbytes_r, %eax + addl %eax, from_r /* from += wsize - nbytes */ + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1_mmx + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1_mmx + +.L_wrap_around_window_mmx: +#define write_r %eax + movl write(%esp), write_r + cmpl write_r, nbytes_r + jbe .L_contiguous_in_window_mmx /* if (write >= nbytes) */ + + addl wsize(%esp), from_r + addl write_r, from_r + subl nbytes_r, from_r /* from += wsize + write - nbytes */ + subl write_r, nbytes_r /* nbytes -= write */ +#undef write_r + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl window(%esp), from_r /* from = window */ + movl write(%esp), nbytes_r /* nbytes = write */ + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + jmp .L_do_copy1_mmx + +.L_contiguous_in_window_mmx: +#define write_r %eax + addl write_r, from_r + subl nbytes_r, from_r /* from += write - nbytes */ +#undef write_r + + cmpl nbytes_r, len_r + jbe .L_do_copy1_mmx /* if (nbytes >= len) */ + + subl nbytes_r, len_r /* len -= nbytes */ + rep movsb + movl out_r, from_r + subl dist_r, from_r /* from = out - dist */ + +.L_do_copy1_mmx: +#undef nbytes_r +#define in_r %esi + movl len_r, %ecx + rep movsb + + movl in(%esp), in_r /* move in back to %esi, toss from */ + movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */ + jmp .L_while_test_mmx + +#undef hold_r +#undef bitslong_r + +#endif /* USE_MMX || RUN_TIME_MMX */ + + +/*** USE_MMX, NO_MMX, and RUNTIME_MMX from here on ***/ + +.L_invalid_distance_code: + /* else { + * strm->msg = "invalid distance code"; + * state->mode = BAD; + * } + */ + movl $.L_invalid_distance_code_msg, %ecx + movl $INFLATE_MODE_BAD, %edx + jmp .L_update_stream_state + +.L_test_for_end_of_block: + /* else if (op & 32) { + * state->mode = TYPE; + * break; + * } + */ + testb $32, %al + jz .L_invalid_literal_length_code /* if ((op & 32) == 0) */ + + movl $0, %ecx + movl $INFLATE_MODE_TYPE, %edx + jmp .L_update_stream_state + +.L_invalid_literal_length_code: + /* else { + * strm->msg = "invalid literal/length code"; + * state->mode = BAD; + * } + */ + movl $.L_invalid_literal_length_code_msg, %ecx + movl $INFLATE_MODE_BAD, %edx + jmp .L_update_stream_state + +.L_invalid_distance_too_far: + /* strm->msg = "invalid distance too far back"; + * state->mode = BAD; + */ + movl in(%esp), in_r /* from_r has in's reg, put in back */ + movl $.L_invalid_distance_too_far_msg, %ecx + movl $INFLATE_MODE_BAD, %edx + jmp .L_update_stream_state + +.L_update_stream_state: + /* set strm->msg = %ecx, strm->state->mode = %edx */ + movl strm_sp(%esp), %eax + testl %ecx, %ecx /* if (msg != NULL) */ + jz .L_skip_msg + movl %ecx, msg_strm(%eax) /* strm->msg = msg */ +.L_skip_msg: + movl state_strm(%eax), %eax /* state = strm->state */ + movl %edx, mode_state(%eax) /* state->mode = edx (BAD | TYPE) */ + jmp .L_break_loop + +.align 32,0x90 +.L_break_loop: + +/* + * Regs: + * + * bits = %ebp when mmx, and in %ebx when non-mmx + * hold = %hold_mm when mmx, and in %ebp when non-mmx + * in = %esi + * out = %edi + */ + +#if defined( USE_MMX ) || defined( RUN_TIME_MMX ) + +#if defined( RUN_TIME_MMX ) + + cmpl $DO_USE_MMX, inflate_fast_use_mmx + jne .L_update_next_in + +#endif /* RUN_TIME_MMX */ + + movl %ebp, %ebx + +.L_update_next_in: + +#endif + +#define strm_r %eax +#define state_r %edx + + /* len = bits >> 3; + * in -= len; + * bits -= len << 3; + * hold &= (1U << bits) - 1; + * state->hold = hold; + * state->bits = bits; + * strm->next_in = in; + * strm->next_out = out; + */ + movl strm_sp(%esp), strm_r + movl %ebx, %ecx + movl state_strm(strm_r), state_r + shrl $3, %ecx + subl %ecx, in_r + shll $3, %ecx + subl %ecx, %ebx + movl out_r, next_out_strm(strm_r) + movl %ebx, bits_state(state_r) + movl %ebx, %ecx + + leal buf(%esp), %ebx + cmpl %ebx, last(%esp) + jne .L_buf_not_used /* if buf != last */ + + subl %ebx, in_r /* in -= buf */ + movl next_in_strm(strm_r), %ebx + movl %ebx, last(%esp) /* last = strm->next_in */ + addl %ebx, in_r /* in += strm->next_in */ + movl avail_in_strm(strm_r), %ebx + subl $11, %ebx + addl %ebx, last(%esp) /* last = &strm->next_in[ avail_in - 11 ] */ + +.L_buf_not_used: + movl in_r, next_in_strm(strm_r) + + movl $1, %ebx + shll %cl, %ebx + decl %ebx + +#if defined( USE_MMX ) || defined( RUN_TIME_MMX ) + +#if defined( RUN_TIME_MMX ) + + cmpl $DO_USE_MMX, inflate_fast_use_mmx + jne .L_update_hold + +#endif /* RUN_TIME_MMX */ + + psrlq used_mm, hold_mm /* hold_mm >>= last bit length */ + movd hold_mm, %ebp + + emms + +.L_update_hold: + +#endif /* USE_MMX || RUN_TIME_MMX */ + + andl %ebx, %ebp + movl %ebp, hold_state(state_r) + +#define last_r %ebx + + /* strm->avail_in = in < last ? 11 + (last - in) : 11 - (in - last) */ + movl last(%esp), last_r + cmpl in_r, last_r + jbe .L_last_is_smaller /* if (in >= last) */ + + subl in_r, last_r /* last -= in */ + addl $11, last_r /* last += 11 */ + movl last_r, avail_in_strm(strm_r) + jmp .L_fixup_out +.L_last_is_smaller: + subl last_r, in_r /* in -= last */ + negl in_r /* in = -in */ + addl $11, in_r /* in += 11 */ + movl in_r, avail_in_strm(strm_r) + +#undef last_r +#define end_r %ebx + +.L_fixup_out: + /* strm->avail_out = out < end ? 257 + (end - out) : 257 - (out - end)*/ + movl end(%esp), end_r + cmpl out_r, end_r + jbe .L_end_is_smaller /* if (out >= end) */ + + subl out_r, end_r /* end -= out */ + addl $257, end_r /* end += 257 */ + movl end_r, avail_out_strm(strm_r) + jmp .L_done +.L_end_is_smaller: + subl end_r, out_r /* out -= end */ + negl out_r /* out = -out */ + addl $257, out_r /* out += 257 */ + movl out_r, avail_out_strm(strm_r) + +#undef end_r +#undef strm_r +#undef state_r + +.L_done: + addl $local_var_size, %esp + popf + popl %ebx + popl %ebp + popl %esi + popl %edi + ret + +#if defined( GAS_ELF ) +/* elf info */ +.type inflate_fast,@function +.size inflate_fast,.-inflate_fast +#endif diff --git a/test/zlib/zlib-1.2.8/contrib/iostream/test.cpp b/test/zlib/zlib-1.2.8/contrib/iostream/test.cpp new file mode 100644 index 000000000..7d265b3b5 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/iostream/test.cpp @@ -0,0 +1,24 @@ + +#include "zfstream.h" + +int main() { + + // Construct a stream object with this filebuffer. Anything sent + // to this stream will go to standard out. + gzofstream os( 1, ios::out ); + + // This text is getting compressed and sent to stdout. + // To prove this, run 'test | zcat'. + os << "Hello, Mommy" << endl; + + os << setcompressionlevel( Z_NO_COMPRESSION ); + os << "hello, hello, hi, ho!" << endl; + + setcompressionlevel( os, Z_DEFAULT_COMPRESSION ) + << "I'm compressing again" << endl; + + os.close(); + + return 0; + +} diff --git a/test/zlib/zlib-1.2.8/contrib/iostream/zfstream.cpp b/test/zlib/zlib-1.2.8/contrib/iostream/zfstream.cpp new file mode 100644 index 000000000..d0cd85faa --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/iostream/zfstream.cpp @@ -0,0 +1,329 @@ + +#include "zfstream.h" + +gzfilebuf::gzfilebuf() : + file(NULL), + mode(0), + own_file_descriptor(0) +{ } + +gzfilebuf::~gzfilebuf() { + + sync(); + if ( own_file_descriptor ) + close(); + +} + +gzfilebuf *gzfilebuf::open( const char *name, + int io_mode ) { + + if ( is_open() ) + return NULL; + + char char_mode[10]; + char *p = char_mode; + + if ( io_mode & ios::in ) { + mode = ios::in; + *p++ = 'r'; + } else if ( io_mode & ios::app ) { + mode = ios::app; + *p++ = 'a'; + } else { + mode = ios::out; + *p++ = 'w'; + } + + if ( io_mode & ios::binary ) { + mode |= ios::binary; + *p++ = 'b'; + } + + // Hard code the compression level + if ( io_mode & (ios::out|ios::app )) { + *p++ = '9'; + } + + // Put the end-of-string indicator + *p = '\0'; + + if ( (file = gzopen(name, char_mode)) == NULL ) + return NULL; + + own_file_descriptor = 1; + + return this; + +} + +gzfilebuf *gzfilebuf::attach( int file_descriptor, + int io_mode ) { + + if ( is_open() ) + return NULL; + + char char_mode[10]; + char *p = char_mode; + + if ( io_mode & ios::in ) { + mode = ios::in; + *p++ = 'r'; + } else if ( io_mode & ios::app ) { + mode = ios::app; + *p++ = 'a'; + } else { + mode = ios::out; + *p++ = 'w'; + } + + if ( io_mode & ios::binary ) { + mode |= ios::binary; + *p++ = 'b'; + } + + // Hard code the compression level + if ( io_mode & (ios::out|ios::app )) { + *p++ = '9'; + } + + // Put the end-of-string indicator + *p = '\0'; + + if ( (file = gzdopen(file_descriptor, char_mode)) == NULL ) + return NULL; + + own_file_descriptor = 0; + + return this; + +} + +gzfilebuf *gzfilebuf::close() { + + if ( is_open() ) { + + sync(); + gzclose( file ); + file = NULL; + + } + + return this; + +} + +int gzfilebuf::setcompressionlevel( int comp_level ) { + + return gzsetparams(file, comp_level, -2); + +} + +int gzfilebuf::setcompressionstrategy( int comp_strategy ) { + + return gzsetparams(file, -2, comp_strategy); + +} + + +streampos gzfilebuf::seekoff( streamoff off, ios::seek_dir dir, int which ) { + + return streampos(EOF); + +} + +int gzfilebuf::underflow() { + + // If the file hasn't been opened for reading, error. + if ( !is_open() || !(mode & ios::in) ) + return EOF; + + // if a buffer doesn't exists, allocate one. + if ( !base() ) { + + if ( (allocate()) == EOF ) + return EOF; + setp(0,0); + + } else { + + if ( in_avail() ) + return (unsigned char) *gptr(); + + if ( out_waiting() ) { + if ( flushbuf() == EOF ) + return EOF; + } + + } + + // Attempt to fill the buffer. + + int result = fillbuf(); + if ( result == EOF ) { + // disable get area + setg(0,0,0); + return EOF; + } + + return (unsigned char) *gptr(); + +} + +int gzfilebuf::overflow( int c ) { + + if ( !is_open() || !(mode & ios::out) ) + return EOF; + + if ( !base() ) { + if ( allocate() == EOF ) + return EOF; + setg(0,0,0); + } else { + if (in_avail()) { + return EOF; + } + if (out_waiting()) { + if (flushbuf() == EOF) + return EOF; + } + } + + int bl = blen(); + setp( base(), base() + bl); + + if ( c != EOF ) { + + *pptr() = c; + pbump(1); + + } + + return 0; + +} + +int gzfilebuf::sync() { + + if ( !is_open() ) + return EOF; + + if ( out_waiting() ) + return flushbuf(); + + return 0; + +} + +int gzfilebuf::flushbuf() { + + int n; + char *q; + + q = pbase(); + n = pptr() - q; + + if ( gzwrite( file, q, n) < n ) + return EOF; + + setp(0,0); + + return 0; + +} + +int gzfilebuf::fillbuf() { + + int required; + char *p; + + p = base(); + + required = blen(); + + int t = gzread( file, p, required ); + + if ( t <= 0) return EOF; + + setg( base(), base(), base()+t); + + return t; + +} + +gzfilestream_common::gzfilestream_common() : + ios( gzfilestream_common::rdbuf() ) +{ } + +gzfilestream_common::~gzfilestream_common() +{ } + +void gzfilestream_common::attach( int fd, int io_mode ) { + + if ( !buffer.attach( fd, io_mode) ) + clear( ios::failbit | ios::badbit ); + else + clear(); + +} + +void gzfilestream_common::open( const char *name, int io_mode ) { + + if ( !buffer.open( name, io_mode ) ) + clear( ios::failbit | ios::badbit ); + else + clear(); + +} + +void gzfilestream_common::close() { + + if ( !buffer.close() ) + clear( ios::failbit | ios::badbit ); + +} + +gzfilebuf *gzfilestream_common::rdbuf() +{ + return &buffer; +} + +gzifstream::gzifstream() : + ios( gzfilestream_common::rdbuf() ) +{ + clear( ios::badbit ); +} + +gzifstream::gzifstream( const char *name, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::open( name, io_mode ); +} + +gzifstream::gzifstream( int fd, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::attach( fd, io_mode ); +} + +gzifstream::~gzifstream() { } + +gzofstream::gzofstream() : + ios( gzfilestream_common::rdbuf() ) +{ + clear( ios::badbit ); +} + +gzofstream::gzofstream( const char *name, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::open( name, io_mode ); +} + +gzofstream::gzofstream( int fd, int io_mode ) : + ios( gzfilestream_common::rdbuf() ) +{ + gzfilestream_common::attach( fd, io_mode ); +} + +gzofstream::~gzofstream() { } diff --git a/test/zlib/zlib-1.2.8/contrib/iostream/zfstream.h b/test/zlib/zlib-1.2.8/contrib/iostream/zfstream.h new file mode 100644 index 000000000..ed79098a3 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/iostream/zfstream.h @@ -0,0 +1,128 @@ + +#ifndef zfstream_h +#define zfstream_h + +#include +#include "zlib.h" + +class gzfilebuf : public streambuf { + +public: + + gzfilebuf( ); + virtual ~gzfilebuf(); + + gzfilebuf *open( const char *name, int io_mode ); + gzfilebuf *attach( int file_descriptor, int io_mode ); + gzfilebuf *close(); + + int setcompressionlevel( int comp_level ); + int setcompressionstrategy( int comp_strategy ); + + inline int is_open() const { return (file !=NULL); } + + virtual streampos seekoff( streamoff, ios::seek_dir, int ); + + virtual int sync(); + +protected: + + virtual int underflow(); + virtual int overflow( int = EOF ); + +private: + + gzFile file; + short mode; + short own_file_descriptor; + + int flushbuf(); + int fillbuf(); + +}; + +class gzfilestream_common : virtual public ios { + + friend class gzifstream; + friend class gzofstream; + friend gzofstream &setcompressionlevel( gzofstream &, int ); + friend gzofstream &setcompressionstrategy( gzofstream &, int ); + +public: + virtual ~gzfilestream_common(); + + void attach( int fd, int io_mode ); + void open( const char *name, int io_mode ); + void close(); + +protected: + gzfilestream_common(); + +private: + gzfilebuf *rdbuf(); + + gzfilebuf buffer; + +}; + +class gzifstream : public gzfilestream_common, public istream { + +public: + + gzifstream(); + gzifstream( const char *name, int io_mode = ios::in ); + gzifstream( int fd, int io_mode = ios::in ); + + virtual ~gzifstream(); + +}; + +class gzofstream : public gzfilestream_common, public ostream { + +public: + + gzofstream(); + gzofstream( const char *name, int io_mode = ios::out ); + gzofstream( int fd, int io_mode = ios::out ); + + virtual ~gzofstream(); + +}; + +template class gzomanip { + friend gzofstream &operator<<(gzofstream &, const gzomanip &); +public: + gzomanip(gzofstream &(*f)(gzofstream &, T), T v) : func(f), val(v) { } +private: + gzofstream &(*func)(gzofstream &, T); + T val; +}; + +template gzofstream &operator<<(gzofstream &s, const gzomanip &m) +{ + return (*m.func)(s, m.val); +} + +inline gzofstream &setcompressionlevel( gzofstream &s, int l ) +{ + (s.rdbuf())->setcompressionlevel(l); + return s; +} + +inline gzofstream &setcompressionstrategy( gzofstream &s, int l ) +{ + (s.rdbuf())->setcompressionstrategy(l); + return s; +} + +inline gzomanip setcompressionlevel(int l) +{ + return gzomanip(&setcompressionlevel,l); +} + +inline gzomanip setcompressionstrategy(int l) +{ + return gzomanip(&setcompressionstrategy,l); +} + +#endif diff --git a/test/zlib/zlib-1.2.8/contrib/iostream2/zstream.h b/test/zlib/zlib-1.2.8/contrib/iostream2/zstream.h new file mode 100644 index 000000000..43d2332b7 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/iostream2/zstream.h @@ -0,0 +1,307 @@ +/* + * + * Copyright (c) 1997 + * Christian Michelsen Research AS + * Advanced Computing + * Fantoftvegen 38, 5036 BERGEN, Norway + * http://www.cmr.no + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Christian Michelsen Research AS makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ + +#ifndef ZSTREAM__H +#define ZSTREAM__H + +/* + * zstream.h - C++ interface to the 'zlib' general purpose compression library + * $Id: zstream.h 1.1 1997-06-25 12:00:56+02 tyge Exp tyge $ + */ + +#include +#include +#include +#include "zlib.h" + +#if defined(_WIN32) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +class zstringlen { +public: + zstringlen(class izstream&); + zstringlen(class ozstream&, const char*); + size_t value() const { return val.word; } +private: + struct Val { unsigned char byte; size_t word; } val; +}; + +// ----------------------------- izstream ----------------------------- + +class izstream +{ + public: + izstream() : m_fp(0) {} + izstream(FILE* fp) : m_fp(0) { open(fp); } + izstream(const char* name) : m_fp(0) { open(name); } + ~izstream() { close(); } + + /* Opens a gzip (.gz) file for reading. + * open() can be used to read a file which is not in gzip format; + * in this case read() will directly read from the file without + * decompression. errno can be checked to distinguish two error + * cases (if errno is zero, the zlib error is Z_MEM_ERROR). + */ + void open(const char* name) { + if (m_fp) close(); + m_fp = ::gzopen(name, "rb"); + } + + void open(FILE* fp) { + SET_BINARY_MODE(fp); + if (m_fp) close(); + m_fp = ::gzdopen(fileno(fp), "rb"); + } + + /* Flushes all pending input if necessary, closes the compressed file + * and deallocates all the (de)compression state. The return value is + * the zlib error number (see function error() below). + */ + int close() { + int r = ::gzclose(m_fp); + m_fp = 0; return r; + } + + /* Binary read the given number of bytes from the compressed file. + */ + int read(void* buf, size_t len) { + return ::gzread(m_fp, buf, len); + } + + /* Returns the error message for the last error which occurred on the + * given compressed file. errnum is set to zlib error number. If an + * error occurred in the file system and not in the compression library, + * errnum is set to Z_ERRNO and the application may consult errno + * to get the exact error code. + */ + const char* error(int* errnum) { + return ::gzerror(m_fp, errnum); + } + + gzFile fp() { return m_fp; } + + private: + gzFile m_fp; +}; + +/* + * Binary read the given (array of) object(s) from the compressed file. + * If the input file was not in gzip format, read() copies the objects number + * of bytes into the buffer. + * returns the number of uncompressed bytes actually read + * (0 for end of file, -1 for error). + */ +template +inline int read(izstream& zs, T* x, Items items) { + return ::gzread(zs.fp(), x, items*sizeof(T)); +} + +/* + * Binary input with the '>' operator. + */ +template +inline izstream& operator>(izstream& zs, T& x) { + ::gzread(zs.fp(), &x, sizeof(T)); + return zs; +} + + +inline zstringlen::zstringlen(izstream& zs) { + zs > val.byte; + if (val.byte == 255) zs > val.word; + else val.word = val.byte; +} + +/* + * Read length of string + the string with the '>' operator. + */ +inline izstream& operator>(izstream& zs, char* x) { + zstringlen len(zs); + ::gzread(zs.fp(), x, len.value()); + x[len.value()] = '\0'; + return zs; +} + +inline char* read_string(izstream& zs) { + zstringlen len(zs); + char* x = new char[len.value()+1]; + ::gzread(zs.fp(), x, len.value()); + x[len.value()] = '\0'; + return x; +} + +// ----------------------------- ozstream ----------------------------- + +class ozstream +{ + public: + ozstream() : m_fp(0), m_os(0) { + } + ozstream(FILE* fp, int level = Z_DEFAULT_COMPRESSION) + : m_fp(0), m_os(0) { + open(fp, level); + } + ozstream(const char* name, int level = Z_DEFAULT_COMPRESSION) + : m_fp(0), m_os(0) { + open(name, level); + } + ~ozstream() { + close(); + } + + /* Opens a gzip (.gz) file for writing. + * The compression level parameter should be in 0..9 + * errno can be checked to distinguish two error cases + * (if errno is zero, the zlib error is Z_MEM_ERROR). + */ + void open(const char* name, int level = Z_DEFAULT_COMPRESSION) { + char mode[4] = "wb\0"; + if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level; + if (m_fp) close(); + m_fp = ::gzopen(name, mode); + } + + /* open from a FILE pointer. + */ + void open(FILE* fp, int level = Z_DEFAULT_COMPRESSION) { + SET_BINARY_MODE(fp); + char mode[4] = "wb\0"; + if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level; + if (m_fp) close(); + m_fp = ::gzdopen(fileno(fp), mode); + } + + /* Flushes all pending output if necessary, closes the compressed file + * and deallocates all the (de)compression state. The return value is + * the zlib error number (see function error() below). + */ + int close() { + if (m_os) { + ::gzwrite(m_fp, m_os->str(), m_os->pcount()); + delete[] m_os->str(); delete m_os; m_os = 0; + } + int r = ::gzclose(m_fp); m_fp = 0; return r; + } + + /* Binary write the given number of bytes into the compressed file. + */ + int write(const void* buf, size_t len) { + return ::gzwrite(m_fp, (voidp) buf, len); + } + + /* Flushes all pending output into the compressed file. The parameter + * _flush is as in the deflate() function. The return value is the zlib + * error number (see function gzerror below). flush() returns Z_OK if + * the flush_ parameter is Z_FINISH and all output could be flushed. + * flush() should be called only when strictly necessary because it can + * degrade compression. + */ + int flush(int _flush) { + os_flush(); + return ::gzflush(m_fp, _flush); + } + + /* Returns the error message for the last error which occurred on the + * given compressed file. errnum is set to zlib error number. If an + * error occurred in the file system and not in the compression library, + * errnum is set to Z_ERRNO and the application may consult errno + * to get the exact error code. + */ + const char* error(int* errnum) { + return ::gzerror(m_fp, errnum); + } + + gzFile fp() { return m_fp; } + + ostream& os() { + if (m_os == 0) m_os = new ostrstream; + return *m_os; + } + + void os_flush() { + if (m_os && m_os->pcount()>0) { + ostrstream* oss = new ostrstream; + oss->fill(m_os->fill()); + oss->flags(m_os->flags()); + oss->precision(m_os->precision()); + oss->width(m_os->width()); + ::gzwrite(m_fp, m_os->str(), m_os->pcount()); + delete[] m_os->str(); delete m_os; m_os = oss; + } + } + + private: + gzFile m_fp; + ostrstream* m_os; +}; + +/* + * Binary write the given (array of) object(s) into the compressed file. + * returns the number of uncompressed bytes actually written + * (0 in case of error). + */ +template +inline int write(ozstream& zs, const T* x, Items items) { + return ::gzwrite(zs.fp(), (voidp) x, items*sizeof(T)); +} + +/* + * Binary output with the '<' operator. + */ +template +inline ozstream& operator<(ozstream& zs, const T& x) { + ::gzwrite(zs.fp(), (voidp) &x, sizeof(T)); + return zs; +} + +inline zstringlen::zstringlen(ozstream& zs, const char* x) { + val.byte = 255; val.word = ::strlen(x); + if (val.word < 255) zs < (val.byte = val.word); + else zs < val; +} + +/* + * Write length of string + the string with the '<' operator. + */ +inline ozstream& operator<(ozstream& zs, const char* x) { + zstringlen len(zs, x); + ::gzwrite(zs.fp(), (voidp) x, len.value()); + return zs; +} + +#ifdef _MSC_VER +inline ozstream& operator<(ozstream& zs, char* const& x) { + return zs < (const char*) x; +} +#endif + +/* + * Ascii write with the << operator; + */ +template +inline ostream& operator<<(ozstream& zs, const T& x) { + zs.os_flush(); + return zs.os() << x; +} + +#endif diff --git a/test/zlib/zlib-1.2.8/contrib/iostream2/zstream_test.cpp b/test/zlib/zlib-1.2.8/contrib/iostream2/zstream_test.cpp new file mode 100644 index 000000000..6273f62d6 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/iostream2/zstream_test.cpp @@ -0,0 +1,25 @@ +#include "zstream.h" +#include +#include +#include + +void main() { + char h[256] = "Hello"; + char* g = "Goodbye"; + ozstream out("temp.gz"); + out < "This works well" < h < g; + out.close(); + + izstream in("temp.gz"); // read it back + char *x = read_string(in), *y = new char[256], z[256]; + in > y > z; + in.close(); + cout << x << endl << y << endl << z << endl; + + out.open("temp.gz"); // try ascii output; zcat temp.gz to see the results + out << setw(50) << setfill('#') << setprecision(20) << x << endl << y << endl << z << endl; + out << z << endl << y << endl << x << endl; + out << 1.1234567890123456789 << endl; + + delete[] x; delete[] y; +} diff --git a/test/zlib/zlib-1.2.8/contrib/iostream3/README b/test/zlib/zlib-1.2.8/contrib/iostream3/README new file mode 100644 index 000000000..f7b319ab9 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/iostream3/README @@ -0,0 +1,35 @@ +These classes provide a C++ stream interface to the zlib library. It allows you +to do things like: + + gzofstream outf("blah.gz"); + outf << "These go into the gzip file " << 123 << endl; + +It does this by deriving a specialized stream buffer for gzipped files, which is +the way Stroustrup would have done it. :-> + +The gzifstream and gzofstream classes were originally written by Kevin Ruland +and made available in the zlib contrib/iostream directory. The older version still +compiles under gcc 2.xx, but not under gcc 3.xx, which sparked the development of +this version. + +The new classes are as standard-compliant as possible, closely following the +approach of the standard library's fstream classes. It compiles under gcc versions +3.2 and 3.3, but not under gcc 2.xx. This is mainly due to changes in the standard +library naming scheme. The new version of gzifstream/gzofstream/gzfilebuf differs +from the previous one in the following respects: +- added showmanyc +- added setbuf, with support for unbuffered output via setbuf(0,0) +- a few bug fixes of stream behavior +- gzipped output file opened with default compression level instead of maximum level +- setcompressionlevel()/strategy() members replaced by single setcompression() + +The code is provided "as is", with the permission to use, copy, modify, distribute +and sell it for any purpose without fee. + +Ludwig Schwardt + + +DSP Lab +Electrical & Electronic Engineering Department +University of Stellenbosch +South Africa diff --git a/test/zlib/zlib-1.2.8/contrib/iostream3/TODO b/test/zlib/zlib-1.2.8/contrib/iostream3/TODO new file mode 100644 index 000000000..7032f97be --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/iostream3/TODO @@ -0,0 +1,17 @@ +Possible upgrades to gzfilebuf: + +- The ability to do putback (e.g. putbackfail) + +- The ability to seek (zlib supports this, but could be slow/tricky) + +- Simultaneous read/write access (does it make sense?) + +- Support for ios_base::ate open mode + +- Locale support? + +- Check public interface to see which calls give problems + (due to dependence on library internals) + +- Override operator<<(ostream&, gzfilebuf*) to allow direct copying + of stream buffer to stream ( i.e. os << is.rdbuf(); ) diff --git a/test/zlib/zlib-1.2.8/contrib/iostream3/test.cc b/test/zlib/zlib-1.2.8/contrib/iostream3/test.cc new file mode 100644 index 000000000..94235334f --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/iostream3/test.cc @@ -0,0 +1,50 @@ +/* + * Test program for gzifstream and gzofstream + * + * by Ludwig Schwardt + * original version by Kevin Ruland + */ + +#include "zfstream.h" +#include // for cout + +int main() { + + gzofstream outf; + gzifstream inf; + char buf[80]; + + outf.open("test1.txt.gz"); + outf << "The quick brown fox sidestepped the lazy canine\n" + << 1.3 << "\nPlan " << 9 << std::endl; + outf.close(); + std::cout << "Wrote the following message to 'test1.txt.gz' (check with zcat or zless):\n" + << "The quick brown fox sidestepped the lazy canine\n" + << 1.3 << "\nPlan " << 9 << std::endl; + + std::cout << "\nReading 'test1.txt.gz' (buffered) produces:\n"; + inf.open("test1.txt.gz"); + while (inf.getline(buf,80,'\n')) { + std::cout << buf << "\t(" << inf.rdbuf()->in_avail() << " chars left in buffer)\n"; + } + inf.close(); + + outf.rdbuf()->pubsetbuf(0,0); + outf.open("test2.txt.gz"); + outf << setcompression(Z_NO_COMPRESSION) + << "The quick brown fox sidestepped the lazy canine\n" + << 1.3 << "\nPlan " << 9 << std::endl; + outf.close(); + std::cout << "\nWrote the same message to 'test2.txt.gz' in uncompressed form"; + + std::cout << "\nReading 'test2.txt.gz' (unbuffered) produces:\n"; + inf.rdbuf()->pubsetbuf(0,0); + inf.open("test2.txt.gz"); + while (inf.getline(buf,80,'\n')) { + std::cout << buf << "\t(" << inf.rdbuf()->in_avail() << " chars left in buffer)\n"; + } + inf.close(); + + return 0; + +} diff --git a/test/zlib/zlib-1.2.8/contrib/iostream3/zfstream.cc b/test/zlib/zlib-1.2.8/contrib/iostream3/zfstream.cc new file mode 100644 index 000000000..94eb93344 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/iostream3/zfstream.cc @@ -0,0 +1,479 @@ +/* + * A C++ I/O streams interface to the zlib gz* functions + * + * by Ludwig Schwardt + * original version by Kevin Ruland + * + * This version is standard-compliant and compatible with gcc 3.x. + */ + +#include "zfstream.h" +#include // for strcpy, strcat, strlen (mode strings) +#include // for BUFSIZ + +// Internal buffer sizes (default and "unbuffered" versions) +#define BIGBUFSIZE BUFSIZ +#define SMALLBUFSIZE 1 + +/*****************************************************************************/ + +// Default constructor +gzfilebuf::gzfilebuf() +: file(NULL), io_mode(std::ios_base::openmode(0)), own_fd(false), + buffer(NULL), buffer_size(BIGBUFSIZE), own_buffer(true) +{ + // No buffers to start with + this->disable_buffer(); +} + +// Destructor +gzfilebuf::~gzfilebuf() +{ + // Sync output buffer and close only if responsible for file + // (i.e. attached streams should be left open at this stage) + this->sync(); + if (own_fd) + this->close(); + // Make sure internal buffer is deallocated + this->disable_buffer(); +} + +// Set compression level and strategy +int +gzfilebuf::setcompression(int comp_level, + int comp_strategy) +{ + return gzsetparams(file, comp_level, comp_strategy); +} + +// Open gzipped file +gzfilebuf* +gzfilebuf::open(const char *name, + std::ios_base::openmode mode) +{ + // Fail if file already open + if (this->is_open()) + return NULL; + // Don't support simultaneous read/write access (yet) + if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) + return NULL; + + // Build mode string for gzopen and check it [27.8.1.3.2] + char char_mode[6] = "\0\0\0\0\0"; + if (!this->open_mode(mode, char_mode)) + return NULL; + + // Attempt to open file + if ((file = gzopen(name, char_mode)) == NULL) + return NULL; + + // On success, allocate internal buffer and set flags + this->enable_buffer(); + io_mode = mode; + own_fd = true; + return this; +} + +// Attach to gzipped file +gzfilebuf* +gzfilebuf::attach(int fd, + std::ios_base::openmode mode) +{ + // Fail if file already open + if (this->is_open()) + return NULL; + // Don't support simultaneous read/write access (yet) + if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) + return NULL; + + // Build mode string for gzdopen and check it [27.8.1.3.2] + char char_mode[6] = "\0\0\0\0\0"; + if (!this->open_mode(mode, char_mode)) + return NULL; + + // Attempt to attach to file + if ((file = gzdopen(fd, char_mode)) == NULL) + return NULL; + + // On success, allocate internal buffer and set flags + this->enable_buffer(); + io_mode = mode; + own_fd = false; + return this; +} + +// Close gzipped file +gzfilebuf* +gzfilebuf::close() +{ + // Fail immediately if no file is open + if (!this->is_open()) + return NULL; + // Assume success + gzfilebuf* retval = this; + // Attempt to sync and close gzipped file + if (this->sync() == -1) + retval = NULL; + if (gzclose(file) < 0) + retval = NULL; + // File is now gone anyway (postcondition [27.8.1.3.8]) + file = NULL; + own_fd = false; + // Destroy internal buffer if it exists + this->disable_buffer(); + return retval; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// Convert int open mode to mode string +bool +gzfilebuf::open_mode(std::ios_base::openmode mode, + char* c_mode) const +{ + bool testb = mode & std::ios_base::binary; + bool testi = mode & std::ios_base::in; + bool testo = mode & std::ios_base::out; + bool testt = mode & std::ios_base::trunc; + bool testa = mode & std::ios_base::app; + + // Check for valid flag combinations - see [27.8.1.3.2] (Table 92) + // Original zfstream hardcoded the compression level to maximum here... + // Double the time for less than 1% size improvement seems + // excessive though - keeping it at the default level + // To change back, just append "9" to the next three mode strings + if (!testi && testo && !testt && !testa) + strcpy(c_mode, "w"); + if (!testi && testo && !testt && testa) + strcpy(c_mode, "a"); + if (!testi && testo && testt && !testa) + strcpy(c_mode, "w"); + if (testi && !testo && !testt && !testa) + strcpy(c_mode, "r"); + // No read/write mode yet +// if (testi && testo && !testt && !testa) +// strcpy(c_mode, "r+"); +// if (testi && testo && testt && !testa) +// strcpy(c_mode, "w+"); + + // Mode string should be empty for invalid combination of flags + if (strlen(c_mode) == 0) + return false; + if (testb) + strcat(c_mode, "b"); + return true; +} + +// Determine number of characters in internal get buffer +std::streamsize +gzfilebuf::showmanyc() +{ + // Calls to underflow will fail if file not opened for reading + if (!this->is_open() || !(io_mode & std::ios_base::in)) + return -1; + // Make sure get area is in use + if (this->gptr() && (this->gptr() < this->egptr())) + return std::streamsize(this->egptr() - this->gptr()); + else + return 0; +} + +// Fill get area from gzipped file +gzfilebuf::int_type +gzfilebuf::underflow() +{ + // If something is left in the get area by chance, return it + // (this shouldn't normally happen, as underflow is only supposed + // to be called when gptr >= egptr, but it serves as error check) + if (this->gptr() && (this->gptr() < this->egptr())) + return traits_type::to_int_type(*(this->gptr())); + + // If the file hasn't been opened for reading, produce error + if (!this->is_open() || !(io_mode & std::ios_base::in)) + return traits_type::eof(); + + // Attempt to fill internal buffer from gzipped file + // (buffer must be guaranteed to exist...) + int bytes_read = gzread(file, buffer, buffer_size); + // Indicates error or EOF + if (bytes_read <= 0) + { + // Reset get area + this->setg(buffer, buffer, buffer); + return traits_type::eof(); + } + // Make all bytes read from file available as get area + this->setg(buffer, buffer, buffer + bytes_read); + + // Return next character in get area + return traits_type::to_int_type(*(this->gptr())); +} + +// Write put area to gzipped file +gzfilebuf::int_type +gzfilebuf::overflow(int_type c) +{ + // Determine whether put area is in use + if (this->pbase()) + { + // Double-check pointer range + if (this->pptr() > this->epptr() || this->pptr() < this->pbase()) + return traits_type::eof(); + // Add extra character to buffer if not EOF + if (!traits_type::eq_int_type(c, traits_type::eof())) + { + *(this->pptr()) = traits_type::to_char_type(c); + this->pbump(1); + } + // Number of characters to write to file + int bytes_to_write = this->pptr() - this->pbase(); + // Overflow doesn't fail if nothing is to be written + if (bytes_to_write > 0) + { + // If the file hasn't been opened for writing, produce error + if (!this->is_open() || !(io_mode & std::ios_base::out)) + return traits_type::eof(); + // If gzipped file won't accept all bytes written to it, fail + if (gzwrite(file, this->pbase(), bytes_to_write) != bytes_to_write) + return traits_type::eof(); + // Reset next pointer to point to pbase on success + this->pbump(-bytes_to_write); + } + } + // Write extra character to file if not EOF + else if (!traits_type::eq_int_type(c, traits_type::eof())) + { + // If the file hasn't been opened for writing, produce error + if (!this->is_open() || !(io_mode & std::ios_base::out)) + return traits_type::eof(); + // Impromptu char buffer (allows "unbuffered" output) + char_type last_char = traits_type::to_char_type(c); + // If gzipped file won't accept this character, fail + if (gzwrite(file, &last_char, 1) != 1) + return traits_type::eof(); + } + + // If you got here, you have succeeded (even if c was EOF) + // The return value should therefore be non-EOF + if (traits_type::eq_int_type(c, traits_type::eof())) + return traits_type::not_eof(c); + else + return c; +} + +// Assign new buffer +std::streambuf* +gzfilebuf::setbuf(char_type* p, + std::streamsize n) +{ + // First make sure stuff is sync'ed, for safety + if (this->sync() == -1) + return NULL; + // If buffering is turned off on purpose via setbuf(0,0), still allocate one... + // "Unbuffered" only really refers to put [27.8.1.4.10], while get needs at + // least a buffer of size 1 (very inefficient though, therefore make it bigger?) + // This follows from [27.5.2.4.3]/12 (gptr needs to point at something, it seems) + if (!p || !n) + { + // Replace existing buffer (if any) with small internal buffer + this->disable_buffer(); + buffer = NULL; + buffer_size = 0; + own_buffer = true; + this->enable_buffer(); + } + else + { + // Replace existing buffer (if any) with external buffer + this->disable_buffer(); + buffer = p; + buffer_size = n; + own_buffer = false; + this->enable_buffer(); + } + return this; +} + +// Write put area to gzipped file (i.e. ensures that put area is empty) +int +gzfilebuf::sync() +{ + return traits_type::eq_int_type(this->overflow(), traits_type::eof()) ? -1 : 0; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// Allocate internal buffer +void +gzfilebuf::enable_buffer() +{ + // If internal buffer required, allocate one + if (own_buffer && !buffer) + { + // Check for buffered vs. "unbuffered" + if (buffer_size > 0) + { + // Allocate internal buffer + buffer = new char_type[buffer_size]; + // Get area starts empty and will be expanded by underflow as need arises + this->setg(buffer, buffer, buffer); + // Setup entire internal buffer as put area. + // The one-past-end pointer actually points to the last element of the buffer, + // so that overflow(c) can safely add the extra character c to the sequence. + // These pointers remain in place for the duration of the buffer + this->setp(buffer, buffer + buffer_size - 1); + } + else + { + // Even in "unbuffered" case, (small?) get buffer is still required + buffer_size = SMALLBUFSIZE; + buffer = new char_type[buffer_size]; + this->setg(buffer, buffer, buffer); + // "Unbuffered" means no put buffer + this->setp(0, 0); + } + } + else + { + // If buffer already allocated, reset buffer pointers just to make sure no + // stale chars are lying around + this->setg(buffer, buffer, buffer); + this->setp(buffer, buffer + buffer_size - 1); + } +} + +// Destroy internal buffer +void +gzfilebuf::disable_buffer() +{ + // If internal buffer exists, deallocate it + if (own_buffer && buffer) + { + // Preserve unbuffered status by zeroing size + if (!this->pbase()) + buffer_size = 0; + delete[] buffer; + buffer = NULL; + this->setg(0, 0, 0); + this->setp(0, 0); + } + else + { + // Reset buffer pointers to initial state if external buffer exists + this->setg(buffer, buffer, buffer); + if (buffer) + this->setp(buffer, buffer + buffer_size - 1); + else + this->setp(0, 0); + } +} + +/*****************************************************************************/ + +// Default constructor initializes stream buffer +gzifstream::gzifstream() +: std::istream(NULL), sb() +{ this->init(&sb); } + +// Initialize stream buffer and open file +gzifstream::gzifstream(const char* name, + std::ios_base::openmode mode) +: std::istream(NULL), sb() +{ + this->init(&sb); + this->open(name, mode); +} + +// Initialize stream buffer and attach to file +gzifstream::gzifstream(int fd, + std::ios_base::openmode mode) +: std::istream(NULL), sb() +{ + this->init(&sb); + this->attach(fd, mode); +} + +// Open file and go into fail() state if unsuccessful +void +gzifstream::open(const char* name, + std::ios_base::openmode mode) +{ + if (!sb.open(name, mode | std::ios_base::in)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Attach to file and go into fail() state if unsuccessful +void +gzifstream::attach(int fd, + std::ios_base::openmode mode) +{ + if (!sb.attach(fd, mode | std::ios_base::in)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Close file +void +gzifstream::close() +{ + if (!sb.close()) + this->setstate(std::ios_base::failbit); +} + +/*****************************************************************************/ + +// Default constructor initializes stream buffer +gzofstream::gzofstream() +: std::ostream(NULL), sb() +{ this->init(&sb); } + +// Initialize stream buffer and open file +gzofstream::gzofstream(const char* name, + std::ios_base::openmode mode) +: std::ostream(NULL), sb() +{ + this->init(&sb); + this->open(name, mode); +} + +// Initialize stream buffer and attach to file +gzofstream::gzofstream(int fd, + std::ios_base::openmode mode) +: std::ostream(NULL), sb() +{ + this->init(&sb); + this->attach(fd, mode); +} + +// Open file and go into fail() state if unsuccessful +void +gzofstream::open(const char* name, + std::ios_base::openmode mode) +{ + if (!sb.open(name, mode | std::ios_base::out)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Attach to file and go into fail() state if unsuccessful +void +gzofstream::attach(int fd, + std::ios_base::openmode mode) +{ + if (!sb.attach(fd, mode | std::ios_base::out)) + this->setstate(std::ios_base::failbit); + else + this->clear(); +} + +// Close file +void +gzofstream::close() +{ + if (!sb.close()) + this->setstate(std::ios_base::failbit); +} diff --git a/test/zlib/zlib-1.2.8/contrib/iostream3/zfstream.h b/test/zlib/zlib-1.2.8/contrib/iostream3/zfstream.h new file mode 100644 index 000000000..8574479ae --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/iostream3/zfstream.h @@ -0,0 +1,466 @@ +/* + * A C++ I/O streams interface to the zlib gz* functions + * + * by Ludwig Schwardt + * original version by Kevin Ruland + * + * This version is standard-compliant and compatible with gcc 3.x. + */ + +#ifndef ZFSTREAM_H +#define ZFSTREAM_H + +#include // not iostream, since we don't need cin/cout +#include +#include "zlib.h" + +/*****************************************************************************/ + +/** + * @brief Gzipped file stream buffer class. + * + * This class implements basic_filebuf for gzipped files. It doesn't yet support + * seeking (allowed by zlib but slow/limited), putback and read/write access + * (tricky). Otherwise, it attempts to be a drop-in replacement for the standard + * file streambuf. +*/ +class gzfilebuf : public std::streambuf +{ +public: + // Default constructor. + gzfilebuf(); + + // Destructor. + virtual + ~gzfilebuf(); + + /** + * @brief Set compression level and strategy on the fly. + * @param comp_level Compression level (see zlib.h for allowed values) + * @param comp_strategy Compression strategy (see zlib.h for allowed values) + * @return Z_OK on success, Z_STREAM_ERROR otherwise. + * + * Unfortunately, these parameters cannot be modified separately, as the + * previous zfstream version assumed. Since the strategy is seldom changed, + * it can default and setcompression(level) then becomes like the old + * setcompressionlevel(level). + */ + int + setcompression(int comp_level, + int comp_strategy = Z_DEFAULT_STRATEGY); + + /** + * @brief Check if file is open. + * @return True if file is open. + */ + bool + is_open() const { return (file != NULL); } + + /** + * @brief Open gzipped file. + * @param name File name. + * @param mode Open mode flags. + * @return @c this on success, NULL on failure. + */ + gzfilebuf* + open(const char* name, + std::ios_base::openmode mode); + + /** + * @brief Attach to already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags. + * @return @c this on success, NULL on failure. + */ + gzfilebuf* + attach(int fd, + std::ios_base::openmode mode); + + /** + * @brief Close gzipped file. + * @return @c this on success, NULL on failure. + */ + gzfilebuf* + close(); + +protected: + /** + * @brief Convert ios open mode int to mode string used by zlib. + * @return True if valid mode flag combination. + */ + bool + open_mode(std::ios_base::openmode mode, + char* c_mode) const; + + /** + * @brief Number of characters available in stream buffer. + * @return Number of characters. + * + * This indicates number of characters in get area of stream buffer. + * These characters can be read without accessing the gzipped file. + */ + virtual std::streamsize + showmanyc(); + + /** + * @brief Fill get area from gzipped file. + * @return First character in get area on success, EOF on error. + * + * This actually reads characters from gzipped file to stream + * buffer. Always buffered. + */ + virtual int_type + underflow(); + + /** + * @brief Write put area to gzipped file. + * @param c Extra character to add to buffer contents. + * @return Non-EOF on success, EOF on error. + * + * This actually writes characters in stream buffer to + * gzipped file. With unbuffered output this is done one + * character at a time. + */ + virtual int_type + overflow(int_type c = traits_type::eof()); + + /** + * @brief Installs external stream buffer. + * @param p Pointer to char buffer. + * @param n Size of external buffer. + * @return @c this on success, NULL on failure. + * + * Call setbuf(0,0) to enable unbuffered output. + */ + virtual std::streambuf* + setbuf(char_type* p, + std::streamsize n); + + /** + * @brief Flush stream buffer to file. + * @return 0 on success, -1 on error. + * + * This calls underflow(EOF) to do the job. + */ + virtual int + sync(); + +// +// Some future enhancements +// +// virtual int_type uflow(); +// virtual int_type pbackfail(int_type c = traits_type::eof()); +// virtual pos_type +// seekoff(off_type off, +// std::ios_base::seekdir way, +// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out); +// virtual pos_type +// seekpos(pos_type sp, +// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out); + +private: + /** + * @brief Allocate internal buffer. + * + * This function is safe to call multiple times. It will ensure + * that a proper internal buffer exists if it is required. If the + * buffer already exists or is external, the buffer pointers will be + * reset to their original state. + */ + void + enable_buffer(); + + /** + * @brief Destroy internal buffer. + * + * This function is safe to call multiple times. It will ensure + * that the internal buffer is deallocated if it exists. In any + * case, it will also reset the buffer pointers. + */ + void + disable_buffer(); + + /** + * Underlying file pointer. + */ + gzFile file; + + /** + * Mode in which file was opened. + */ + std::ios_base::openmode io_mode; + + /** + * @brief True if this object owns file descriptor. + * + * This makes the class responsible for closing the file + * upon destruction. + */ + bool own_fd; + + /** + * @brief Stream buffer. + * + * For simplicity this remains allocated on the free store for the + * entire life span of the gzfilebuf object, unless replaced by setbuf. + */ + char_type* buffer; + + /** + * @brief Stream buffer size. + * + * Defaults to system default buffer size (typically 8192 bytes). + * Modified by setbuf. + */ + std::streamsize buffer_size; + + /** + * @brief True if this object owns stream buffer. + * + * This makes the class responsible for deleting the buffer + * upon destruction. + */ + bool own_buffer; +}; + +/*****************************************************************************/ + +/** + * @brief Gzipped file input stream class. + * + * This class implements ifstream for gzipped files. Seeking and putback + * is not supported yet. +*/ +class gzifstream : public std::istream +{ +public: + // Default constructor + gzifstream(); + + /** + * @brief Construct stream on gzipped file to be opened. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::in). + */ + explicit + gzifstream(const char* name, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * @brief Construct stream on already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::in). + */ + explicit + gzifstream(int fd, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * Obtain underlying stream buffer. + */ + gzfilebuf* + rdbuf() const + { return const_cast(&sb); } + + /** + * @brief Check if file is open. + * @return True if file is open. + */ + bool + is_open() { return sb.is_open(); } + + /** + * @brief Open gzipped file. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::in). + * + * Stream will be in state good() if file opens successfully; + * otherwise in state fail(). This differs from the behavior of + * ifstream, which never sets the state to good() and therefore + * won't allow you to reuse the stream for a second file unless + * you manually clear() the state. The choice is a matter of + * convenience. + */ + void + open(const char* name, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * @brief Attach to already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::in). + * + * Stream will be in state good() if attach succeeded; otherwise + * in state fail(). + */ + void + attach(int fd, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * @brief Close gzipped file. + * + * Stream will be in state fail() if close failed. + */ + void + close(); + +private: + /** + * Underlying stream buffer. + */ + gzfilebuf sb; +}; + +/*****************************************************************************/ + +/** + * @brief Gzipped file output stream class. + * + * This class implements ofstream for gzipped files. Seeking and putback + * is not supported yet. +*/ +class gzofstream : public std::ostream +{ +public: + // Default constructor + gzofstream(); + + /** + * @brief Construct stream on gzipped file to be opened. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::out). + */ + explicit + gzofstream(const char* name, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * @brief Construct stream on already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::out). + */ + explicit + gzofstream(int fd, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * Obtain underlying stream buffer. + */ + gzfilebuf* + rdbuf() const + { return const_cast(&sb); } + + /** + * @brief Check if file is open. + * @return True if file is open. + */ + bool + is_open() { return sb.is_open(); } + + /** + * @brief Open gzipped file. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::out). + * + * Stream will be in state good() if file opens successfully; + * otherwise in state fail(). This differs from the behavior of + * ofstream, which never sets the state to good() and therefore + * won't allow you to reuse the stream for a second file unless + * you manually clear() the state. The choice is a matter of + * convenience. + */ + void + open(const char* name, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * @brief Attach to already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::out). + * + * Stream will be in state good() if attach succeeded; otherwise + * in state fail(). + */ + void + attach(int fd, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * @brief Close gzipped file. + * + * Stream will be in state fail() if close failed. + */ + void + close(); + +private: + /** + * Underlying stream buffer. + */ + gzfilebuf sb; +}; + +/*****************************************************************************/ + +/** + * @brief Gzipped file output stream manipulator class. + * + * This class defines a two-argument manipulator for gzofstream. It is used + * as base for the setcompression(int,int) manipulator. +*/ +template + class gzomanip2 + { + public: + // Allows insertor to peek at internals + template + friend gzofstream& + operator<<(gzofstream&, + const gzomanip2&); + + // Constructor + gzomanip2(gzofstream& (*f)(gzofstream&, T1, T2), + T1 v1, + T2 v2); + private: + // Underlying manipulator function + gzofstream& + (*func)(gzofstream&, T1, T2); + + // Arguments for manipulator function + T1 val1; + T2 val2; + }; + +/*****************************************************************************/ + +// Manipulator function thunks through to stream buffer +inline gzofstream& +setcompression(gzofstream &gzs, int l, int s = Z_DEFAULT_STRATEGY) +{ + (gzs.rdbuf())->setcompression(l, s); + return gzs; +} + +// Manipulator constructor stores arguments +template + inline + gzomanip2::gzomanip2(gzofstream &(*f)(gzofstream &, T1, T2), + T1 v1, + T2 v2) + : func(f), val1(v1), val2(v2) + { } + +// Insertor applies underlying manipulator function to stream +template + inline gzofstream& + operator<<(gzofstream& s, const gzomanip2& m) + { return (*m.func)(s, m.val1, m.val2); } + +// Insert this onto stream to simplify setting of compression level +inline gzomanip2 +setcompression(int l, int s = Z_DEFAULT_STRATEGY) +{ return gzomanip2(&setcompression, l, s); } + +#endif // ZFSTREAM_H diff --git a/test/zlib/zlib-1.2.8/contrib/masmx64/bld_ml64.bat b/test/zlib/zlib-1.2.8/contrib/masmx64/bld_ml64.bat new file mode 100644 index 000000000..f74bcef5b --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/masmx64/bld_ml64.bat @@ -0,0 +1,2 @@ +ml64.exe /Flinffasx64 /c /Zi inffasx64.asm +ml64.exe /Flgvmat64 /c /Zi gvmat64.asm diff --git a/test/zlib/zlib-1.2.8/contrib/masmx64/gvmat64.asm b/test/zlib/zlib-1.2.8/contrib/masmx64/gvmat64.asm new file mode 100644 index 000000000..c1817f1be --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/masmx64/gvmat64.asm @@ -0,0 +1,553 @@ +;uInt longest_match_x64( +; deflate_state *s, +; IPos cur_match); /* current match */ + +; gvmat64.asm -- Asm portion of the optimized longest_match for 32 bits x86_64 +; (AMD64 on Athlon 64, Opteron, Phenom +; and Intel EM64T on Pentium 4 with EM64T, Pentium D, Core 2 Duo, Core I5/I7) +; Copyright (C) 1995-2010 Jean-loup Gailly, Brian Raiter and Gilles Vollant. +; +; File written by Gilles Vollant, by converting to assembly the longest_match +; from Jean-loup Gailly in deflate.c of zLib and infoZip zip. +; +; and by taking inspiration on asm686 with masm, optimised assembly code +; from Brian Raiter, written 1998 +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must not +; claim that you wrote the original software. If you use this software +; in a product, an acknowledgment in the product documentation would be +; appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must not be +; misrepresented as being the original software +; 3. This notice may not be removed or altered from any source distribution. +; +; +; +; http://www.zlib.net +; http://www.winimage.com/zLibDll +; http://www.muppetlabs.com/~breadbox/software/assembly.html +; +; to compile this file for infozip Zip, I use option: +; ml64.exe /Flgvmat64 /c /Zi /DINFOZIP gvmat64.asm +; +; to compile this file for zLib, I use option: +; ml64.exe /Flgvmat64 /c /Zi gvmat64.asm +; Be carrefull to adapt zlib1222add below to your version of zLib +; (if you use a version of zLib before 1.0.4 or after 1.2.2.2, change +; value of zlib1222add later) +; +; This file compile with Microsoft Macro Assembler (x64) for AMD64 +; +; ml64.exe is given with Visual Studio 2005/2008/2010 and Windows WDK +; +; (you can get Windows WDK with ml64 for AMD64 from +; http://www.microsoft.com/whdc/Devtools/wdk/default.mspx for low price) +; + + +;uInt longest_match(s, cur_match) +; deflate_state *s; +; IPos cur_match; /* current match */ +.code +longest_match PROC + + +;LocalVarsSize equ 88 + LocalVarsSize equ 72 + +; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12 +; free register : r14,r15 +; register can be saved : rsp + + chainlenwmask equ rsp + 8 - LocalVarsSize ; high word: current chain len + ; low word: s->wmask +;window equ rsp + xx - LocalVarsSize ; local copy of s->window ; stored in r10 +;windowbestlen equ rsp + xx - LocalVarsSize ; s->window + bestlen , use r10+r11 +;scanstart equ rsp + xx - LocalVarsSize ; first two bytes of string ; stored in r12w +;scanend equ rsp + xx - LocalVarsSize ; last two bytes of string use ebx +;scanalign equ rsp + xx - LocalVarsSize ; dword-misalignment of string r13 +;bestlen equ rsp + xx - LocalVarsSize ; size of best match so far -> r11d +;scan equ rsp + xx - LocalVarsSize ; ptr to string wanting match -> r9 +IFDEF INFOZIP +ELSE + nicematch equ (rsp + 16 - LocalVarsSize) ; a good enough match size +ENDIF + +save_rdi equ rsp + 24 - LocalVarsSize +save_rsi equ rsp + 32 - LocalVarsSize +save_rbx equ rsp + 40 - LocalVarsSize +save_rbp equ rsp + 48 - LocalVarsSize +save_r12 equ rsp + 56 - LocalVarsSize +save_r13 equ rsp + 64 - LocalVarsSize +;save_r14 equ rsp + 72 - LocalVarsSize +;save_r15 equ rsp + 80 - LocalVarsSize + + +; summary of register usage +; scanend ebx +; scanendw bx +; chainlenwmask edx +; curmatch rsi +; curmatchd esi +; windowbestlen r8 +; scanalign r9 +; scanalignd r9d +; window r10 +; bestlen r11 +; bestlend r11d +; scanstart r12d +; scanstartw r12w +; scan r13 +; nicematch r14d +; limit r15 +; limitd r15d +; prev rcx + +; all the +4 offsets are due to the addition of pending_buf_size (in zlib +; in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, remove the +4). +; Note : these value are good with a 8 bytes boundary pack structure + + + MAX_MATCH equ 258 + MIN_MATCH equ 3 + MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1) + + +;;; Offsets for fields in the deflate_state structure. These numbers +;;; are calculated from the definition of deflate_state, with the +;;; assumption that the compiler will dword-align the fields. (Thus, +;;; changing the definition of deflate_state could easily cause this +;;; program to crash horribly, without so much as a warning at +;;; compile time. Sigh.) + +; all the +zlib1222add offsets are due to the addition of fields +; in zlib in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). +; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). +; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). + + +IFDEF INFOZIP + +_DATA SEGMENT +COMM window_size:DWORD +; WMask ; 7fff +COMM window:BYTE:010040H +COMM prev:WORD:08000H +; MatchLen : unused +; PrevMatch : unused +COMM strstart:DWORD +COMM match_start:DWORD +; Lookahead : ignore +COMM prev_length:DWORD ; PrevLen +COMM max_chain_length:DWORD +COMM good_match:DWORD +COMM nice_match:DWORD +prev_ad equ OFFSET prev +window_ad equ OFFSET window +nicematch equ nice_match +_DATA ENDS +WMask equ 07fffh + +ELSE + + IFNDEF zlib1222add + zlib1222add equ 8 + ENDIF +dsWSize equ 56+zlib1222add+(zlib1222add/2) +dsWMask equ 64+zlib1222add+(zlib1222add/2) +dsWindow equ 72+zlib1222add +dsPrev equ 88+zlib1222add +dsMatchLen equ 128+zlib1222add +dsPrevMatch equ 132+zlib1222add +dsStrStart equ 140+zlib1222add +dsMatchStart equ 144+zlib1222add +dsLookahead equ 148+zlib1222add +dsPrevLen equ 152+zlib1222add +dsMaxChainLen equ 156+zlib1222add +dsGoodMatch equ 172+zlib1222add +dsNiceMatch equ 176+zlib1222add + +window_size equ [ rcx + dsWSize] +WMask equ [ rcx + dsWMask] +window_ad equ [ rcx + dsWindow] +prev_ad equ [ rcx + dsPrev] +strstart equ [ rcx + dsStrStart] +match_start equ [ rcx + dsMatchStart] +Lookahead equ [ rcx + dsLookahead] ; 0ffffffffh on infozip +prev_length equ [ rcx + dsPrevLen] +max_chain_length equ [ rcx + dsMaxChainLen] +good_match equ [ rcx + dsGoodMatch] +nice_match equ [ rcx + dsNiceMatch] +ENDIF + +; parameter 1 in r8(deflate state s), param 2 in rdx (cur match) + +; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and +; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp +; +; All registers must be preserved across the call, except for +; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch. + + + +;;; Save registers that the compiler may be using, and adjust esp to +;;; make room for our stack frame. + + +;;; Retrieve the function arguments. r8d will hold cur_match +;;; throughout the entire function. edx will hold the pointer to the +;;; deflate_state structure during the function's setup (before +;;; entering the main loop. + +; parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match) + +; this clear high 32 bits of r8, which can be garbage in both r8 and rdx + + mov [save_rdi],rdi + mov [save_rsi],rsi + mov [save_rbx],rbx + mov [save_rbp],rbp +IFDEF INFOZIP + mov r8d,ecx +ELSE + mov r8d,edx +ENDIF + mov [save_r12],r12 + mov [save_r13],r13 +; mov [save_r14],r14 +; mov [save_r15],r15 + + +;;; uInt wmask = s->w_mask; +;;; unsigned chain_length = s->max_chain_length; +;;; if (s->prev_length >= s->good_match) { +;;; chain_length >>= 2; +;;; } + + mov edi, prev_length + mov esi, good_match + mov eax, WMask + mov ebx, max_chain_length + cmp edi, esi + jl LastMatchGood + shr ebx, 2 +LastMatchGood: + +;;; chainlen is decremented once beforehand so that the function can +;;; use the sign flag instead of the zero flag for the exit test. +;;; It is then shifted into the high word, to make room for the wmask +;;; value, which it will always accompany. + + dec ebx + shl ebx, 16 + or ebx, eax + +;;; on zlib only +;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + +IFDEF INFOZIP + mov [chainlenwmask], ebx +; on infozip nice_match = [nice_match] +ELSE + mov eax, nice_match + mov [chainlenwmask], ebx + mov r10d, Lookahead + cmp r10d, eax + cmovnl r10d, eax + mov [nicematch],r10d +ENDIF + +;;; register Bytef *scan = s->window + s->strstart; + mov r10, window_ad + mov ebp, strstart + lea r13, [r10 + rbp] + +;;; Determine how many bytes the scan ptr is off from being +;;; dword-aligned. + + mov r9,r13 + neg r13 + and r13,3 + +;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? +;;; s->strstart - (IPos)MAX_DIST(s) : NIL; +IFDEF INFOZIP + mov eax,07efah ; MAX_DIST = (WSIZE-MIN_LOOKAHEAD) (0x8000-(3+8+1)) +ELSE + mov eax, window_size + sub eax, MIN_LOOKAHEAD +ENDIF + xor edi,edi + sub ebp, eax + + mov r11d, prev_length + + cmovng ebp,edi + +;;; int best_len = s->prev_length; + + +;;; Store the sum of s->window + best_len in esi locally, and in esi. + + lea rsi,[r10+r11] + +;;; register ush scan_start = *(ushf*)scan; +;;; register ush scan_end = *(ushf*)(scan+best_len-1); +;;; Posf *prev = s->prev; + + movzx r12d,word ptr [r9] + movzx ebx, word ptr [r9 + r11 - 1] + + mov rdi, prev_ad + +;;; Jump into the main loop. + + mov edx, [chainlenwmask] + + cmp bx,word ptr [rsi + r8 - 1] + jz LookupLoopIsZero + +LookupLoop1: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry1: + cmp bx,word ptr [rsi + r8 - 1] + jz LookupLoopIsZero + +LookupLoop2: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry2: + cmp bx,word ptr [rsi + r8 - 1] + jz LookupLoopIsZero + +LookupLoop4: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry4: + + cmp bx,word ptr [rsi + r8 - 1] + jnz LookupLoop1 + jmp LookupLoopIsZero + + +;;; do { +;;; match = s->window + cur_match; +;;; if (*(ushf*)(match+best_len-1) != scan_end || +;;; *(ushf*)match != scan_start) continue; +;;; [...] +;;; } while ((cur_match = prev[cur_match & wmask]) > limit +;;; && --chain_length != 0); +;;; +;;; Here is the inner loop of the function. The function will spend the +;;; majority of its time in this loop, and majority of that time will +;;; be spent in the first ten instructions. +;;; +;;; Within this loop: +;;; ebx = scanend +;;; r8d = curmatch +;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) +;;; esi = windowbestlen - i.e., (window + bestlen) +;;; edi = prev +;;; ebp = limit + +LookupLoop: + and r8d, edx + + movzx r8d, word ptr [rdi + r8*2] + cmp r8d, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow + +LoopEntry: + + cmp bx,word ptr [rsi + r8 - 1] + jnz LookupLoop1 +LookupLoopIsZero: + cmp r12w, word ptr [r10 + r8] + jnz LookupLoop1 + + +;;; Store the current value of chainlen. + mov [chainlenwmask], edx + +;;; Point edi to the string under scrutiny, and esi to the string we +;;; are hoping to match it up with. In actuality, esi and edi are +;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is +;;; initialized to -(MAX_MATCH_8 - scanalign). + + lea rsi,[r8+r10] + mov rdx, 0fffffffffffffef8h; -(MAX_MATCH_8) + lea rsi, [rsi + r13 + 0108h] ;MAX_MATCH_8] + lea rdi, [r9 + r13 + 0108h] ;MAX_MATCH_8] + + prefetcht1 [rsi+rdx] + prefetcht1 [rdi+rdx] + + +;;; Test the strings for equality, 8 bytes at a time. At the end, +;;; adjust rdx so that it is offset to the exact byte that mismatched. +;;; +;;; We already know at this point that the first three bytes of the +;;; strings match each other, and they can be safely passed over before +;;; starting the compare loop. So what this code does is skip over 0-3 +;;; bytes, as much as necessary in order to dword-align the edi +;;; pointer. (rsi will still be misaligned three times out of four.) +;;; +;;; It should be confessed that this loop usually does not represent +;;; much of the total running time. Replacing it with a more +;;; straightforward "rep cmpsb" would not drastically degrade +;;; performance. + + +LoopCmps: + mov rax, [rsi + rdx] + xor rax, [rdi + rdx] + jnz LeaveLoopCmps + + mov rax, [rsi + rdx + 8] + xor rax, [rdi + rdx + 8] + jnz LeaveLoopCmps8 + + + mov rax, [rsi + rdx + 8+8] + xor rax, [rdi + rdx + 8+8] + jnz LeaveLoopCmps16 + + add rdx,8+8+8 + + jnz short LoopCmps + jmp short LenMaximum +LeaveLoopCmps16: add rdx,8 +LeaveLoopCmps8: add rdx,8 +LeaveLoopCmps: + + test eax, 0000FFFFh + jnz LenLower + + test eax,0ffffffffh + + jnz LenLower32 + + add rdx,4 + shr rax,32 + or ax,ax + jnz LenLower + +LenLower32: + shr eax,16 + add rdx,2 +LenLower: sub al, 1 + adc rdx, 0 +;;; Calculate the length of the match. If it is longer than MAX_MATCH, +;;; then automatically accept it as the best possible match and leave. + + lea rax, [rdi + rdx] + sub rax, r9 + cmp eax, MAX_MATCH + jge LenMaximum + +;;; If the length of the match is not longer than the best match we +;;; have so far, then forget it and return to the lookup loop. +;/////////////////////////////////// + + cmp eax, r11d + jg LongerMatch + + lea rsi,[r10+r11] + + mov rdi, prev_ad + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; s->match_start = cur_match; +;;; best_len = len; +;;; if (len >= nice_match) break; +;;; scan_end = *(ushf*)(scan+best_len-1); + +LongerMatch: + mov r11d, eax + mov match_start, r8d + cmp eax, [nicematch] + jge LeaveNow + + lea rsi,[r10+rax] + + movzx ebx, word ptr [r9 + rax - 1] + mov rdi, prev_ad + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; Accept the current string, with the maximum possible length. + +LenMaximum: + mov r11d,MAX_MATCH + mov match_start, r8d + +;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; +;;; return s->lookahead; + +LeaveNow: +IFDEF INFOZIP + mov eax,r11d +ELSE + mov eax, Lookahead + cmp r11d, eax + cmovng eax, r11d +ENDIF + +;;; Restore the stack and return from whence we came. + + + mov rsi,[save_rsi] + mov rdi,[save_rdi] + mov rbx,[save_rbx] + mov rbp,[save_rbp] + mov r12,[save_r12] + mov r13,[save_r13] +; mov r14,[save_r14] +; mov r15,[save_r15] + + + ret 0 +; please don't remove this string ! +; Your can freely use gvmat64 in any free or commercial app +; but it is far better don't remove the string in the binary! + db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0 +longest_match ENDP + +match_init PROC + ret 0 +match_init ENDP + + +END diff --git a/test/zlib/zlib-1.2.8/contrib/masmx64/inffas8664.c b/test/zlib/zlib-1.2.8/contrib/masmx64/inffas8664.c new file mode 100644 index 000000000..aa861a333 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/masmx64/inffas8664.c @@ -0,0 +1,186 @@ +/* inffas8664.c is a hand tuned assembler version of inffast.c - fast decoding + * version for AMD64 on Windows using Microsoft C compiler + * + * Copyright (C) 1995-2003 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Copyright (C) 2003 Chris Anderson + * Please use the copyright conditions above. + * + * 2005 - Adaptation to Microsoft C Compiler for AMD64 by Gilles Vollant + * + * inffas8664.c call function inffas8664fnc in inffasx64.asm + * inffasx64.asm is automatically convert from AMD64 portion of inffas86.c + * + * Dec-29-2003 -- I added AMD64 inflate asm support. This version is also + * slightly quicker on x86 systems because, instead of using rep movsb to copy + * data, it uses rep movsw, which moves data in 2-byte chunks instead of single + * bytes. I've tested the AMD64 code on a Fedora Core 1 + the x86_64 updates + * from http://fedora.linux.duke.edu/fc1_x86_64 + * which is running on an Athlon 64 3000+ / Gigabyte GA-K8VT800M system with + * 1GB ram. The 64-bit version is about 4% faster than the 32-bit version, + * when decompressing mozilla-source-1.3.tar.gz. + * + * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from + * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at + * the moment. I have successfully compiled and tested this code with gcc2.96, + * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S + * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX + * enabled. I will attempt to merge the MMX code into this version. Newer + * versions of this and inffast.S can be found at + * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/ + * + */ + +#include +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* Mark Adler's comments from inffast.c: */ + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ + + + + typedef struct inffast_ar { +/* 64 32 x86 x86_64 */ +/* ar offset register */ +/* 0 0 */ void *esp; /* esp save */ +/* 8 4 */ void *ebp; /* ebp save */ +/* 16 8 */ unsigned char FAR *in; /* esi rsi local strm->next_in */ +/* 24 12 */ unsigned char FAR *last; /* r9 while in < last */ +/* 32 16 */ unsigned char FAR *out; /* edi rdi local strm->next_out */ +/* 40 20 */ unsigned char FAR *beg; /* inflate()'s init next_out */ +/* 48 24 */ unsigned char FAR *end; /* r10 while out < end */ +/* 56 28 */ unsigned char FAR *window;/* size of window, wsize!=0 */ +/* 64 32 */ code const FAR *lcode; /* ebp rbp local strm->lencode */ +/* 72 36 */ code const FAR *dcode; /* r11 local strm->distcode */ +/* 80 40 */ size_t /*unsigned long */hold; /* edx rdx local strm->hold */ +/* 88 44 */ unsigned bits; /* ebx rbx local strm->bits */ +/* 92 48 */ unsigned wsize; /* window size */ +/* 96 52 */ unsigned write; /* window write index */ +/*100 56 */ unsigned lmask; /* r12 mask for lcode */ +/*104 60 */ unsigned dmask; /* r13 mask for dcode */ +/*108 64 */ unsigned len; /* r14 match length */ +/*112 68 */ unsigned dist; /* r15 match distance */ +/*116 72 */ unsigned status; /* set when state chng*/ + } type_ar; +#ifdef ASMINF + +void inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + type_ar ar; + void inffas8664fnc(struct inffast_ar * par); + + + +#if (defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 )) || (defined(_MSC_VER) && defined(_M_AMD64)) +#define PAD_AVAIL_IN 6 +#define PAD_AVAIL_OUT 258 +#else +#define PAD_AVAIL_IN 5 +#define PAD_AVAIL_OUT 257 +#endif + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + + ar.in = strm->next_in; + ar.last = ar.in + (strm->avail_in - PAD_AVAIL_IN); + ar.out = strm->next_out; + ar.beg = ar.out - (start - strm->avail_out); + ar.end = ar.out + (strm->avail_out - PAD_AVAIL_OUT); + ar.wsize = state->wsize; + ar.write = state->wnext; + ar.window = state->window; + ar.hold = state->hold; + ar.bits = state->bits; + ar.lcode = state->lencode; + ar.dcode = state->distcode; + ar.lmask = (1U << state->lenbits) - 1; + ar.dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + + /* align in on 1/2 hold size boundary */ + while (((size_t)(void *)ar.in & (sizeof(ar.hold) / 2 - 1)) != 0) { + ar.hold += (unsigned long)*ar.in++ << ar.bits; + ar.bits += 8; + } + + inffas8664fnc(&ar); + + if (ar.status > 1) { + if (ar.status == 2) + strm->msg = "invalid literal/length code"; + else if (ar.status == 3) + strm->msg = "invalid distance code"; + else + strm->msg = "invalid distance too far back"; + state->mode = BAD; + } + else if ( ar.status == 1 ) { + state->mode = TYPE; + } + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + ar.len = ar.bits >> 3; + ar.in -= ar.len; + ar.bits -= ar.len << 3; + ar.hold &= (1U << ar.bits) - 1; + + /* update state and return */ + strm->next_in = ar.in; + strm->next_out = ar.out; + strm->avail_in = (unsigned)(ar.in < ar.last ? + PAD_AVAIL_IN + (ar.last - ar.in) : + PAD_AVAIL_IN - (ar.in - ar.last)); + strm->avail_out = (unsigned)(ar.out < ar.end ? + PAD_AVAIL_OUT + (ar.end - ar.out) : + PAD_AVAIL_OUT - (ar.out - ar.end)); + state->hold = (unsigned long)ar.hold; + state->bits = ar.bits; + return; +} + +#endif diff --git a/test/zlib/zlib-1.2.8/contrib/masmx64/inffasx64.asm b/test/zlib/zlib-1.2.8/contrib/masmx64/inffasx64.asm new file mode 100644 index 000000000..41ec82392 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/masmx64/inffasx64.asm @@ -0,0 +1,396 @@ +; inffasx64.asm is a hand tuned assembler version of inffast.c - fast decoding +; version for AMD64 on Windows using Microsoft C compiler +; +; inffasx64.asm is automatically convert from AMD64 portion of inffas86.c +; inffasx64.asm is called by inffas8664.c, which contain more info. + + +; to compile this file, I use option +; ml64.exe /Flinffasx64 /c /Zi inffasx64.asm +; with Microsoft Macro Assembler (x64) for AMD64 +; + +; This file compile with Microsoft Macro Assembler (x64) for AMD64 +; +; ml64.exe is given with Visual Studio 2005/2008/2010 and Windows WDK +; +; (you can get Windows WDK with ml64 for AMD64 from +; http://www.microsoft.com/whdc/Devtools/wdk/default.mspx for low price) +; + + +.code +inffas8664fnc PROC + +; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and +; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp +; +; All registers must be preserved across the call, except for +; rax, rcx, rdx, r8, r-9, r10, and r11, which are scratch. + + + mov [rsp-8],rsi + mov [rsp-16],rdi + mov [rsp-24],r12 + mov [rsp-32],r13 + mov [rsp-40],r14 + mov [rsp-48],r15 + mov [rsp-56],rbx + + mov rax,rcx + + mov [rax+8], rbp ; /* save regs rbp and rsp */ + mov [rax], rsp + + mov rsp, rax ; /* make rsp point to &ar */ + + mov rsi, [rsp+16] ; /* rsi = in */ + mov rdi, [rsp+32] ; /* rdi = out */ + mov r9, [rsp+24] ; /* r9 = last */ + mov r10, [rsp+48] ; /* r10 = end */ + mov rbp, [rsp+64] ; /* rbp = lcode */ + mov r11, [rsp+72] ; /* r11 = dcode */ + mov rdx, [rsp+80] ; /* rdx = hold */ + mov ebx, [rsp+88] ; /* ebx = bits */ + mov r12d, [rsp+100] ; /* r12d = lmask */ + mov r13d, [rsp+104] ; /* r13d = dmask */ + ; /* r14d = len */ + ; /* r15d = dist */ + + + cld + cmp r10, rdi + je L_one_time ; /* if only one decode left */ + cmp r9, rsi + + jne L_do_loop + + +L_one_time: + mov r8, r12 ; /* r8 = lmask */ + cmp bl, 32 + ja L_get_length_code_one_time + + lodsd ; /* eax = *(uint *)in++ */ + mov cl, bl ; /* cl = bits, needs it for shifting */ + add bl, 32 ; /* bits += 32 */ + shl rax, cl + or rdx, rax ; /* hold |= *((uint *)in)++ << bits */ + jmp L_get_length_code_one_time + +ALIGN 4 +L_while_test: + cmp r10, rdi + jbe L_break_loop + cmp r9, rsi + jbe L_break_loop + +L_do_loop: + mov r8, r12 ; /* r8 = lmask */ + cmp bl, 32 + ja L_get_length_code ; /* if (32 < bits) */ + + lodsd ; /* eax = *(uint *)in++ */ + mov cl, bl ; /* cl = bits, needs it for shifting */ + add bl, 32 ; /* bits += 32 */ + shl rax, cl + or rdx, rax ; /* hold |= *((uint *)in)++ << bits */ + +L_get_length_code: + and r8, rdx ; /* r8 &= hold */ + mov eax, [rbp+r8*4] ; /* eax = lcode[hold & lmask] */ + + mov cl, ah ; /* cl = this.bits */ + sub bl, ah ; /* bits -= this.bits */ + shr rdx, cl ; /* hold >>= this.bits */ + + test al, al + jnz L_test_for_length_base ; /* if (op != 0) 45.7% */ + + mov r8, r12 ; /* r8 = lmask */ + shr eax, 16 ; /* output this.val char */ + stosb + +L_get_length_code_one_time: + and r8, rdx ; /* r8 &= hold */ + mov eax, [rbp+r8*4] ; /* eax = lcode[hold & lmask] */ + +L_dolen: + mov cl, ah ; /* cl = this.bits */ + sub bl, ah ; /* bits -= this.bits */ + shr rdx, cl ; /* hold >>= this.bits */ + + test al, al + jnz L_test_for_length_base ; /* if (op != 0) 45.7% */ + + shr eax, 16 ; /* output this.val char */ + stosb + jmp L_while_test + +ALIGN 4 +L_test_for_length_base: + mov r14d, eax ; /* len = this */ + shr r14d, 16 ; /* len = this.val */ + mov cl, al + + test al, 16 + jz L_test_for_second_level_length ; /* if ((op & 16) == 0) 8% */ + and cl, 15 ; /* op &= 15 */ + jz L_decode_distance ; /* if (!op) */ + +L_add_bits_to_len: + sub bl, cl + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx ; /* eax &= hold */ + shr rdx, cl + add r14d, eax ; /* len += hold & mask[op] */ + +L_decode_distance: + mov r8, r13 ; /* r8 = dmask */ + cmp bl, 32 + ja L_get_distance_code ; /* if (32 < bits) */ + + lodsd ; /* eax = *(uint *)in++ */ + mov cl, bl ; /* cl = bits, needs it for shifting */ + add bl, 32 ; /* bits += 32 */ + shl rax, cl + or rdx, rax ; /* hold |= *((uint *)in)++ << bits */ + +L_get_distance_code: + and r8, rdx ; /* r8 &= hold */ + mov eax, [r11+r8*4] ; /* eax = dcode[hold & dmask] */ + +L_dodist: + mov r15d, eax ; /* dist = this */ + shr r15d, 16 ; /* dist = this.val */ + mov cl, ah + sub bl, ah ; /* bits -= this.bits */ + shr rdx, cl ; /* hold >>= this.bits */ + mov cl, al ; /* cl = this.op */ + + test al, 16 ; /* if ((op & 16) == 0) */ + jz L_test_for_second_level_dist + and cl, 15 ; /* op &= 15 */ + jz L_check_dist_one + +L_add_bits_to_dist: + sub bl, cl + xor eax, eax + inc eax + shl eax, cl + dec eax ; /* (1 << op) - 1 */ + and eax, edx ; /* eax &= hold */ + shr rdx, cl + add r15d, eax ; /* dist += hold & ((1 << op) - 1) */ + +L_check_window: + mov r8, rsi ; /* save in so from can use it's reg */ + mov rax, rdi + sub rax, [rsp+40] ; /* nbytes = out - beg */ + + cmp eax, r15d + jb L_clip_window ; /* if (dist > nbytes) 4.2% */ + + mov ecx, r14d ; /* ecx = len */ + mov rsi, rdi + sub rsi, r15 ; /* from = out - dist */ + + sar ecx, 1 + jnc L_copy_two ; /* if len % 2 == 0 */ + + rep movsw + mov al, [rsi] + mov [rdi], al + inc rdi + + mov rsi, r8 ; /* move in back to %rsi, toss from */ + jmp L_while_test + +L_copy_two: + rep movsw + mov rsi, r8 ; /* move in back to %rsi, toss from */ + jmp L_while_test + +ALIGN 4 +L_check_dist_one: + cmp r15d, 1 ; /* if dist 1, is a memset */ + jne L_check_window + cmp [rsp+40], rdi ; /* if out == beg, outside window */ + je L_check_window + + mov ecx, r14d ; /* ecx = len */ + mov al, [rdi-1] + mov ah, al + + sar ecx, 1 + jnc L_set_two + mov [rdi], al + inc rdi + +L_set_two: + rep stosw + jmp L_while_test + +ALIGN 4 +L_test_for_second_level_length: + test al, 64 + jnz L_test_for_end_of_block ; /* if ((op & 64) != 0) */ + + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx ; /* eax &= hold */ + add eax, r14d ; /* eax += len */ + mov eax, [rbp+rax*4] ; /* eax = lcode[val+(hold&mask[op])]*/ + jmp L_dolen + +ALIGN 4 +L_test_for_second_level_dist: + test al, 64 + jnz L_invalid_distance_code ; /* if ((op & 64) != 0) */ + + xor eax, eax + inc eax + shl eax, cl + dec eax + and eax, edx ; /* eax &= hold */ + add eax, r15d ; /* eax += dist */ + mov eax, [r11+rax*4] ; /* eax = dcode[val+(hold&mask[op])]*/ + jmp L_dodist + +ALIGN 4 +L_clip_window: + mov ecx, eax ; /* ecx = nbytes */ + mov eax, [rsp+92] ; /* eax = wsize, prepare for dist cmp */ + neg ecx ; /* nbytes = -nbytes */ + + cmp eax, r15d + jb L_invalid_distance_too_far ; /* if (dist > wsize) */ + + add ecx, r15d ; /* nbytes = dist - nbytes */ + cmp dword ptr [rsp+96], 0 + jne L_wrap_around_window ; /* if (write != 0) */ + + mov rsi, [rsp+56] ; /* from = window */ + sub eax, ecx ; /* eax -= nbytes */ + add rsi, rax ; /* from += wsize - nbytes */ + + mov eax, r14d ; /* eax = len */ + cmp r14d, ecx + jbe L_do_copy ; /* if (nbytes >= len) */ + + sub eax, ecx ; /* eax -= nbytes */ + rep movsb + mov rsi, rdi + sub rsi, r15 ; /* from = &out[ -dist ] */ + jmp L_do_copy + +ALIGN 4 +L_wrap_around_window: + mov eax, [rsp+96] ; /* eax = write */ + cmp ecx, eax + jbe L_contiguous_in_window ; /* if (write >= nbytes) */ + + mov esi, [rsp+92] ; /* from = wsize */ + add rsi, [rsp+56] ; /* from += window */ + add rsi, rax ; /* from += write */ + sub rsi, rcx ; /* from -= nbytes */ + sub ecx, eax ; /* nbytes -= write */ + + mov eax, r14d ; /* eax = len */ + cmp eax, ecx + jbe L_do_copy ; /* if (nbytes >= len) */ + + sub eax, ecx ; /* len -= nbytes */ + rep movsb + mov rsi, [rsp+56] ; /* from = window */ + mov ecx, [rsp+96] ; /* nbytes = write */ + cmp eax, ecx + jbe L_do_copy ; /* if (nbytes >= len) */ + + sub eax, ecx ; /* len -= nbytes */ + rep movsb + mov rsi, rdi + sub rsi, r15 ; /* from = out - dist */ + jmp L_do_copy + +ALIGN 4 +L_contiguous_in_window: + mov rsi, [rsp+56] ; /* rsi = window */ + add rsi, rax + sub rsi, rcx ; /* from += write - nbytes */ + + mov eax, r14d ; /* eax = len */ + cmp eax, ecx + jbe L_do_copy ; /* if (nbytes >= len) */ + + sub eax, ecx ; /* len -= nbytes */ + rep movsb + mov rsi, rdi + sub rsi, r15 ; /* from = out - dist */ + jmp L_do_copy ; /* if (nbytes >= len) */ + +ALIGN 4 +L_do_copy: + mov ecx, eax ; /* ecx = len */ + rep movsb + + mov rsi, r8 ; /* move in back to %esi, toss from */ + jmp L_while_test + +L_test_for_end_of_block: + test al, 32 + jz L_invalid_literal_length_code + mov dword ptr [rsp+116], 1 + jmp L_break_loop_with_status + +L_invalid_literal_length_code: + mov dword ptr [rsp+116], 2 + jmp L_break_loop_with_status + +L_invalid_distance_code: + mov dword ptr [rsp+116], 3 + jmp L_break_loop_with_status + +L_invalid_distance_too_far: + mov dword ptr [rsp+116], 4 + jmp L_break_loop_with_status + +L_break_loop: + mov dword ptr [rsp+116], 0 + +L_break_loop_with_status: +; /* put in, out, bits, and hold back into ar and pop esp */ + mov [rsp+16], rsi ; /* in */ + mov [rsp+32], rdi ; /* out */ + mov [rsp+88], ebx ; /* bits */ + mov [rsp+80], rdx ; /* hold */ + + mov rax, [rsp] ; /* restore rbp and rsp */ + mov rbp, [rsp+8] + mov rsp, rax + + + + mov rsi,[rsp-8] + mov rdi,[rsp-16] + mov r12,[rsp-24] + mov r13,[rsp-32] + mov r14,[rsp-40] + mov r15,[rsp-48] + mov rbx,[rsp-56] + + ret 0 +; : +; : "m" (ar) +; : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi", +; "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15" +; ); + +inffas8664fnc ENDP +;_TEXT ENDS +END diff --git a/test/zlib/zlib-1.2.8/contrib/masmx64/readme.txt b/test/zlib/zlib-1.2.8/contrib/masmx64/readme.txt new file mode 100644 index 000000000..652571c7a --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/masmx64/readme.txt @@ -0,0 +1,31 @@ +Summary +------- +This directory contains ASM implementations of the functions +longest_match() and inflate_fast(), for 64 bits x86 (both AMD64 and Intel EM64t), +for use with Microsoft Macro Assembler (x64) for AMD64 and Microsoft C++ 64 bits. + +gvmat64.asm is written by Gilles Vollant (2005), by using Brian Raiter 686/32 bits + assembly optimized version from Jean-loup Gailly original longest_match function + +inffasx64.asm and inffas8664.c were written by Chris Anderson, by optimizing + original function from Mark Adler + +Use instructions +---------------- +Assemble the .asm files using MASM and put the object files into the zlib source +directory. You can also get object files here: + + http://www.winimage.com/zLibDll/zlib124_masm_obj.zip + +define ASMV and ASMINF in your project. Include inffas8664.c in your source tree, +and inffasx64.obj and gvmat64.obj as object to link. + + +Build instructions +------------------ +run bld_64.bat with Microsoft Macro Assembler (x64) for AMD64 (ml64.exe) + +ml64.exe is given with Visual Studio 2005, Windows 2003 server DDK + +You can get Windows 2003 server DDK with ml64 and cl for AMD64 from + http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price) diff --git a/test/zlib/zlib-1.2.8/contrib/masmx86/bld_ml32.bat b/test/zlib/zlib-1.2.8/contrib/masmx86/bld_ml32.bat new file mode 100644 index 000000000..fcf5755e4 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/masmx86/bld_ml32.bat @@ -0,0 +1,2 @@ +ml /coff /Zi /c /Flmatch686.lst match686.asm +ml /coff /Zi /c /Flinffas32.lst inffas32.asm diff --git a/test/zlib/zlib-1.2.8/contrib/masmx86/inffas32.asm b/test/zlib/zlib-1.2.8/contrib/masmx86/inffas32.asm new file mode 100644 index 000000000..cb37a81e4 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/masmx86/inffas32.asm @@ -0,0 +1,1080 @@ +;/* inffas32.asm is a hand tuned assembler version of inffast.c -- fast decoding +; * +; * inffas32.asm is derivated from inffas86.c, with translation of assembly code +; * +; * Copyright (C) 1995-2003 Mark Adler +; * For conditions of distribution and use, see copyright notice in zlib.h +; * +; * Copyright (C) 2003 Chris Anderson +; * Please use the copyright conditions above. +; * +; * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from +; * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at +; * the moment. I have successfully compiled and tested this code with gcc2.96, +; * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S +; * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX +; * enabled. I will attempt to merge the MMX code into this version. Newer +; * versions of this and inffast.S can be found at +; * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/ +; * +; * 2005 : modification by Gilles Vollant +; */ +; For Visual C++ 4.x and higher and ML 6.x and higher +; ml.exe is in directory \MASM611C of Win95 DDK +; ml.exe is also distributed in http://www.masm32.com/masmdl.htm +; and in VC++2003 toolkit at http://msdn.microsoft.com/visualc/vctoolkit2003/ +; +; +; compile with command line option +; ml /coff /Zi /c /Flinffas32.lst inffas32.asm + +; if you define NO_GZIP (see inflate.h), compile with +; ml /coff /Zi /c /Flinffas32.lst /DNO_GUNZIP inffas32.asm + + +; zlib122sup is 0 fort zlib 1.2.2.1 and lower +; zlib122sup is 8 fort zlib 1.2.2.2 and more (with addition of dmax and head +; in inflate_state in inflate.h) +zlib1222sup equ 8 + + +IFDEF GUNZIP + INFLATE_MODE_TYPE equ 11 + INFLATE_MODE_BAD equ 26 +ELSE + IFNDEF NO_GUNZIP + INFLATE_MODE_TYPE equ 11 + INFLATE_MODE_BAD equ 26 + ELSE + INFLATE_MODE_TYPE equ 3 + INFLATE_MODE_BAD equ 17 + ENDIF +ENDIF + + +; 75 "inffast.S" +;FILE "inffast.S" + +;;;GLOBAL _inflate_fast + +;;;SECTION .text + + + + .586p + .mmx + + name inflate_fast_x86 + .MODEL FLAT + +_DATA segment +inflate_fast_use_mmx: + dd 1 + + +_TEXT segment + + + +ALIGN 4 + db 'Fast decoding Code from Chris Anderson' + db 0 + +ALIGN 4 +invalid_literal_length_code_msg: + db 'invalid literal/length code' + db 0 + +ALIGN 4 +invalid_distance_code_msg: + db 'invalid distance code' + db 0 + +ALIGN 4 +invalid_distance_too_far_msg: + db 'invalid distance too far back' + db 0 + + +ALIGN 4 +inflate_fast_mask: +dd 0 +dd 1 +dd 3 +dd 7 +dd 15 +dd 31 +dd 63 +dd 127 +dd 255 +dd 511 +dd 1023 +dd 2047 +dd 4095 +dd 8191 +dd 16383 +dd 32767 +dd 65535 +dd 131071 +dd 262143 +dd 524287 +dd 1048575 +dd 2097151 +dd 4194303 +dd 8388607 +dd 16777215 +dd 33554431 +dd 67108863 +dd 134217727 +dd 268435455 +dd 536870911 +dd 1073741823 +dd 2147483647 +dd 4294967295 + + +mode_state equ 0 ;/* state->mode */ +wsize_state equ (32+zlib1222sup) ;/* state->wsize */ +write_state equ (36+4+zlib1222sup) ;/* state->write */ +window_state equ (40+4+zlib1222sup) ;/* state->window */ +hold_state equ (44+4+zlib1222sup) ;/* state->hold */ +bits_state equ (48+4+zlib1222sup) ;/* state->bits */ +lencode_state equ (64+4+zlib1222sup) ;/* state->lencode */ +distcode_state equ (68+4+zlib1222sup) ;/* state->distcode */ +lenbits_state equ (72+4+zlib1222sup) ;/* state->lenbits */ +distbits_state equ (76+4+zlib1222sup) ;/* state->distbits */ + + +;;SECTION .text +; 205 "inffast.S" +;GLOBAL inflate_fast_use_mmx + +;SECTION .data + + +; GLOBAL inflate_fast_use_mmx:object +;.size inflate_fast_use_mmx, 4 +; 226 "inffast.S" +;SECTION .text + +ALIGN 4 +_inflate_fast proc near +.FPO (16, 4, 0, 0, 1, 0) + push edi + push esi + push ebp + push ebx + pushfd + sub esp,64 + cld + + + + + mov esi, [esp+88] + mov edi, [esi+28] + + + + + + + + mov edx, [esi+4] + mov eax, [esi+0] + + add edx,eax + sub edx,11 + + mov [esp+44],eax + mov [esp+20],edx + + mov ebp, [esp+92] + mov ecx, [esi+16] + mov ebx, [esi+12] + + sub ebp,ecx + neg ebp + add ebp,ebx + + sub ecx,257 + add ecx,ebx + + mov [esp+60],ebx + mov [esp+40],ebp + mov [esp+16],ecx +; 285 "inffast.S" + mov eax, [edi+lencode_state] + mov ecx, [edi+distcode_state] + + mov [esp+8],eax + mov [esp+12],ecx + + mov eax,1 + mov ecx, [edi+lenbits_state] + shl eax,cl + dec eax + mov [esp+0],eax + + mov eax,1 + mov ecx, [edi+distbits_state] + shl eax,cl + dec eax + mov [esp+4],eax + + mov eax, [edi+wsize_state] + mov ecx, [edi+write_state] + mov edx, [edi+window_state] + + mov [esp+52],eax + mov [esp+48],ecx + mov [esp+56],edx + + mov ebp, [edi+hold_state] + mov ebx, [edi+bits_state] +; 321 "inffast.S" + mov esi, [esp+44] + mov ecx, [esp+20] + cmp ecx,esi + ja L_align_long + + add ecx,11 + sub ecx,esi + mov eax,12 + sub eax,ecx + lea edi, [esp+28] + rep movsb + mov ecx,eax + xor eax,eax + rep stosb + lea esi, [esp+28] + mov [esp+20],esi + jmp L_is_aligned + + +L_align_long: + test esi,3 + jz L_is_aligned + xor eax,eax + mov al, [esi] + inc esi + mov ecx,ebx + add ebx,8 + shl eax,cl + or ebp,eax + jmp L_align_long + +L_is_aligned: + mov edi, [esp+60] +; 366 "inffast.S" +L_check_mmx: + cmp dword ptr [inflate_fast_use_mmx],2 + je L_init_mmx + ja L_do_loop + + push eax + push ebx + push ecx + push edx + pushfd + mov eax, [esp] + xor dword ptr [esp],0200000h + + + + + popfd + pushfd + pop edx + xor edx,eax + jz L_dont_use_mmx + xor eax,eax + cpuid + cmp ebx,0756e6547h + jne L_dont_use_mmx + cmp ecx,06c65746eh + jne L_dont_use_mmx + cmp edx,049656e69h + jne L_dont_use_mmx + mov eax,1 + cpuid + shr eax,8 + and eax,15 + cmp eax,6 + jne L_dont_use_mmx + test edx,0800000h + jnz L_use_mmx + jmp L_dont_use_mmx +L_use_mmx: + mov dword ptr [inflate_fast_use_mmx],2 + jmp L_check_mmx_pop +L_dont_use_mmx: + mov dword ptr [inflate_fast_use_mmx],3 +L_check_mmx_pop: + pop edx + pop ecx + pop ebx + pop eax + jmp L_check_mmx +; 426 "inffast.S" +ALIGN 4 +L_do_loop: +; 437 "inffast.S" + cmp bl,15 + ja L_get_length_code + + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + +L_get_length_code: + mov edx, [esp+0] + mov ecx, [esp+8] + and edx,ebp + mov eax, [ecx+edx*4] + +L_dolen: + + + + + + + mov cl,ah + sub bl,ah + shr ebp,cl + + + + + + + test al,al + jnz L_test_for_length_base + + shr eax,16 + stosb + +L_while_test: + + + cmp [esp+16],edi + jbe L_break_loop + + cmp [esp+20],esi + ja L_do_loop + jmp L_break_loop + +L_test_for_length_base: +; 502 "inffast.S" + mov edx,eax + shr edx,16 + mov cl,al + + test al,16 + jz L_test_for_second_level_length + and cl,15 + jz L_save_len + cmp bl,cl + jae L_add_bits_to_len + + mov ch,cl + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + mov cl,ch + +L_add_bits_to_len: + mov eax,1 + shl eax,cl + dec eax + sub bl,cl + and eax,ebp + shr ebp,cl + add edx,eax + +L_save_len: + mov [esp+24],edx + + +L_decode_distance: +; 549 "inffast.S" + cmp bl,15 + ja L_get_distance_code + + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + +L_get_distance_code: + mov edx, [esp+4] + mov ecx, [esp+12] + and edx,ebp + mov eax, [ecx+edx*4] + + +L_dodist: + mov edx,eax + shr edx,16 + mov cl,ah + sub bl,ah + shr ebp,cl +; 584 "inffast.S" + mov cl,al + + test al,16 + jz L_test_for_second_level_dist + and cl,15 + jz L_check_dist_one + cmp bl,cl + jae L_add_bits_to_dist + + mov ch,cl + xor eax,eax + lodsw + mov cl,bl + add bl,16 + shl eax,cl + or ebp,eax + mov cl,ch + +L_add_bits_to_dist: + mov eax,1 + shl eax,cl + dec eax + sub bl,cl + and eax,ebp + shr ebp,cl + add edx,eax + jmp L_check_window + +L_check_window: +; 625 "inffast.S" + mov [esp+44],esi + mov eax,edi + sub eax, [esp+40] + + cmp eax,edx + jb L_clip_window + + mov ecx, [esp+24] + mov esi,edi + sub esi,edx + + sub ecx,3 + mov al, [esi] + mov [edi],al + mov al, [esi+1] + mov dl, [esi+2] + add esi,3 + mov [edi+1],al + mov [edi+2],dl + add edi,3 + rep movsb + + mov esi, [esp+44] + jmp L_while_test + +ALIGN 4 +L_check_dist_one: + cmp edx,1 + jne L_check_window + cmp [esp+40],edi + je L_check_window + + dec edi + mov ecx, [esp+24] + mov al, [edi] + sub ecx,3 + + mov [edi+1],al + mov [edi+2],al + mov [edi+3],al + add edi,4 + rep stosb + + jmp L_while_test + +ALIGN 4 +L_test_for_second_level_length: + + + + + test al,64 + jnz L_test_for_end_of_block + + mov eax,1 + shl eax,cl + dec eax + and eax,ebp + add eax,edx + mov edx, [esp+8] + mov eax, [edx+eax*4] + jmp L_dolen + +ALIGN 4 +L_test_for_second_level_dist: + + + + + test al,64 + jnz L_invalid_distance_code + + mov eax,1 + shl eax,cl + dec eax + and eax,ebp + add eax,edx + mov edx, [esp+12] + mov eax, [edx+eax*4] + jmp L_dodist + +ALIGN 4 +L_clip_window: +; 721 "inffast.S" + mov ecx,eax + mov eax, [esp+52] + neg ecx + mov esi, [esp+56] + + cmp eax,edx + jb L_invalid_distance_too_far + + add ecx,edx + cmp dword ptr [esp+48],0 + jne L_wrap_around_window + + sub eax,ecx + add esi,eax +; 749 "inffast.S" + mov eax, [esp+24] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + jmp L_do_copy1 + + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + jmp L_do_copy1 + +L_wrap_around_window: +; 793 "inffast.S" + mov eax, [esp+48] + cmp ecx,eax + jbe L_contiguous_in_window + + add esi, [esp+52] + add esi,eax + sub esi,ecx + sub ecx,eax + + + mov eax, [esp+24] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi, [esp+56] + mov ecx, [esp+48] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + jmp L_do_copy1 + +L_contiguous_in_window: +; 836 "inffast.S" + add esi,eax + sub esi,ecx + + + mov eax, [esp+24] + cmp eax,ecx + jbe L_do_copy1 + + sub eax,ecx + rep movsb + mov esi,edi + sub esi,edx + +L_do_copy1: +; 862 "inffast.S" + mov ecx,eax + rep movsb + + mov esi, [esp+44] + jmp L_while_test +; 878 "inffast.S" +ALIGN 4 +L_init_mmx: + emms + + + + + + movd mm0,ebp + mov ebp,ebx +; 896 "inffast.S" + movd mm4,dword ptr [esp+0] + movq mm3,mm4 + movd mm5,dword ptr [esp+4] + movq mm2,mm5 + pxor mm1,mm1 + mov ebx, [esp+8] + jmp L_do_loop_mmx + +ALIGN 4 +L_do_loop_mmx: + psrlq mm0,mm1 + + cmp ebp,32 + ja L_get_length_code_mmx + + movd mm6,ebp + movd mm7,dword ptr [esi] + add esi,4 + psllq mm7,mm6 + add ebp,32 + por mm0,mm7 + +L_get_length_code_mmx: + pand mm4,mm0 + movd eax,mm4 + movq mm4,mm3 + mov eax, [ebx+eax*4] + +L_dolen_mmx: + movzx ecx,ah + movd mm1,ecx + sub ebp,ecx + + test al,al + jnz L_test_for_length_base_mmx + + shr eax,16 + stosb + +L_while_test_mmx: + + + cmp [esp+16],edi + jbe L_break_loop + + cmp [esp+20],esi + ja L_do_loop_mmx + jmp L_break_loop + +L_test_for_length_base_mmx: + + mov edx,eax + shr edx,16 + + test al,16 + jz L_test_for_second_level_length_mmx + and eax,15 + jz L_decode_distance_mmx + + psrlq mm0,mm1 + movd mm1,eax + movd ecx,mm0 + sub ebp,eax + and ecx, [inflate_fast_mask+eax*4] + add edx,ecx + +L_decode_distance_mmx: + psrlq mm0,mm1 + + cmp ebp,32 + ja L_get_dist_code_mmx + + movd mm6,ebp + movd mm7,dword ptr [esi] + add esi,4 + psllq mm7,mm6 + add ebp,32 + por mm0,mm7 + +L_get_dist_code_mmx: + mov ebx, [esp+12] + pand mm5,mm0 + movd eax,mm5 + movq mm5,mm2 + mov eax, [ebx+eax*4] + +L_dodist_mmx: + + movzx ecx,ah + mov ebx,eax + shr ebx,16 + sub ebp,ecx + movd mm1,ecx + + test al,16 + jz L_test_for_second_level_dist_mmx + and eax,15 + jz L_check_dist_one_mmx + +L_add_bits_to_dist_mmx: + psrlq mm0,mm1 + movd mm1,eax + movd ecx,mm0 + sub ebp,eax + and ecx, [inflate_fast_mask+eax*4] + add ebx,ecx + +L_check_window_mmx: + mov [esp+44],esi + mov eax,edi + sub eax, [esp+40] + + cmp eax,ebx + jb L_clip_window_mmx + + mov ecx,edx + mov esi,edi + sub esi,ebx + + sub ecx,3 + mov al, [esi] + mov [edi],al + mov al, [esi+1] + mov dl, [esi+2] + add esi,3 + mov [edi+1],al + mov [edi+2],dl + add edi,3 + rep movsb + + mov esi, [esp+44] + mov ebx, [esp+8] + jmp L_while_test_mmx + +ALIGN 4 +L_check_dist_one_mmx: + cmp ebx,1 + jne L_check_window_mmx + cmp [esp+40],edi + je L_check_window_mmx + + dec edi + mov ecx,edx + mov al, [edi] + sub ecx,3 + + mov [edi+1],al + mov [edi+2],al + mov [edi+3],al + add edi,4 + rep stosb + + mov ebx, [esp+8] + jmp L_while_test_mmx + +ALIGN 4 +L_test_for_second_level_length_mmx: + test al,64 + jnz L_test_for_end_of_block + + and eax,15 + psrlq mm0,mm1 + movd ecx,mm0 + and ecx, [inflate_fast_mask+eax*4] + add ecx,edx + mov eax, [ebx+ecx*4] + jmp L_dolen_mmx + +ALIGN 4 +L_test_for_second_level_dist_mmx: + test al,64 + jnz L_invalid_distance_code + + and eax,15 + psrlq mm0,mm1 + movd ecx,mm0 + and ecx, [inflate_fast_mask+eax*4] + mov eax, [esp+12] + add ecx,ebx + mov eax, [eax+ecx*4] + jmp L_dodist_mmx + +ALIGN 4 +L_clip_window_mmx: + + mov ecx,eax + mov eax, [esp+52] + neg ecx + mov esi, [esp+56] + + cmp eax,ebx + jb L_invalid_distance_too_far + + add ecx,ebx + cmp dword ptr [esp+48],0 + jne L_wrap_around_window_mmx + + sub eax,ecx + add esi,eax + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + jmp L_do_copy1_mmx + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + jmp L_do_copy1_mmx + +L_wrap_around_window_mmx: + + mov eax, [esp+48] + cmp ecx,eax + jbe L_contiguous_in_window_mmx + + add esi, [esp+52] + add esi,eax + sub esi,ecx + sub ecx,eax + + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi, [esp+56] + mov ecx, [esp+48] + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + jmp L_do_copy1_mmx + +L_contiguous_in_window_mmx: + + add esi,eax + sub esi,ecx + + + cmp edx,ecx + jbe L_do_copy1_mmx + + sub edx,ecx + rep movsb + mov esi,edi + sub esi,ebx + +L_do_copy1_mmx: + + + mov ecx,edx + rep movsb + + mov esi, [esp+44] + mov ebx, [esp+8] + jmp L_while_test_mmx +; 1174 "inffast.S" +L_invalid_distance_code: + + + + + + mov ecx, invalid_distance_code_msg + mov edx,INFLATE_MODE_BAD + jmp L_update_stream_state + +L_test_for_end_of_block: + + + + + + test al,32 + jz L_invalid_literal_length_code + + mov ecx,0 + mov edx,INFLATE_MODE_TYPE + jmp L_update_stream_state + +L_invalid_literal_length_code: + + + + + + mov ecx, invalid_literal_length_code_msg + mov edx,INFLATE_MODE_BAD + jmp L_update_stream_state + +L_invalid_distance_too_far: + + + + mov esi, [esp+44] + mov ecx, invalid_distance_too_far_msg + mov edx,INFLATE_MODE_BAD + jmp L_update_stream_state + +L_update_stream_state: + + mov eax, [esp+88] + test ecx,ecx + jz L_skip_msg + mov [eax+24],ecx +L_skip_msg: + mov eax, [eax+28] + mov [eax+mode_state],edx + jmp L_break_loop + +ALIGN 4 +L_break_loop: +; 1243 "inffast.S" + cmp dword ptr [inflate_fast_use_mmx],2 + jne L_update_next_in + + + + mov ebx,ebp + +L_update_next_in: +; 1266 "inffast.S" + mov eax, [esp+88] + mov ecx,ebx + mov edx, [eax+28] + shr ecx,3 + sub esi,ecx + shl ecx,3 + sub ebx,ecx + mov [eax+12],edi + mov [edx+bits_state],ebx + mov ecx,ebx + + lea ebx, [esp+28] + cmp [esp+20],ebx + jne L_buf_not_used + + sub esi,ebx + mov ebx, [eax+0] + mov [esp+20],ebx + add esi,ebx + mov ebx, [eax+4] + sub ebx,11 + add [esp+20],ebx + +L_buf_not_used: + mov [eax+0],esi + + mov ebx,1 + shl ebx,cl + dec ebx + + + + + + cmp dword ptr [inflate_fast_use_mmx],2 + jne L_update_hold + + + + psrlq mm0,mm1 + movd ebp,mm0 + + emms + +L_update_hold: + + + + and ebp,ebx + mov [edx+hold_state],ebp + + + + + mov ebx, [esp+20] + cmp ebx,esi + jbe L_last_is_smaller + + sub ebx,esi + add ebx,11 + mov [eax+4],ebx + jmp L_fixup_out +L_last_is_smaller: + sub esi,ebx + neg esi + add esi,11 + mov [eax+4],esi + + + + +L_fixup_out: + + mov ebx, [esp+16] + cmp ebx,edi + jbe L_end_is_smaller + + sub ebx,edi + add ebx,257 + mov [eax+16],ebx + jmp L_done +L_end_is_smaller: + sub edi,ebx + neg edi + add edi,257 + mov [eax+16],edi + + + + + +L_done: + add esp,64 + popfd + pop ebx + pop ebp + pop esi + pop edi + ret +_inflate_fast endp + +_TEXT ends +end diff --git a/test/zlib/zlib-1.2.8/contrib/masmx86/match686.asm b/test/zlib/zlib-1.2.8/contrib/masmx86/match686.asm new file mode 100644 index 000000000..69e0eed01 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/masmx86/match686.asm @@ -0,0 +1,479 @@ +; match686.asm -- Asm portion of the optimized longest_match for 32 bits x86 +; Copyright (C) 1995-1996 Jean-loup Gailly, Brian Raiter and Gilles Vollant. +; File written by Gilles Vollant, by converting match686.S from Brian Raiter +; for MASM. This is as assembly version of longest_match +; from Jean-loup Gailly in deflate.c +; +; http://www.zlib.net +; http://www.winimage.com/zLibDll +; http://www.muppetlabs.com/~breadbox/software/assembly.html +; +; For Visual C++ 4.x and higher and ML 6.x and higher +; ml.exe is distributed in +; http://www.microsoft.com/downloads/details.aspx?FamilyID=7a1c9da0-0510-44a2-b042-7ef370530c64 +; +; this file contain two implementation of longest_match +; +; this longest_match was written by Brian raiter (1998), optimized for Pentium Pro +; (and the faster known version of match_init on modern Core 2 Duo and AMD Phenom) +; +; for using an assembly version of longest_match, you need define ASMV in project +; +; compile the asm file running +; ml /coff /Zi /c /Flmatch686.lst match686.asm +; and do not include match686.obj in your project +; +; note: contrib of zLib 1.2.3 and earlier contained both a deprecated version for +; Pentium (prior Pentium Pro) and this version for Pentium Pro and modern processor +; with autoselect (with cpu detection code) +; if you want support the old pentium optimization, you can still use these version +; +; this file is not optimized for old pentium, but it compatible with all x86 32 bits +; processor (starting 80386) +; +; +; see below : zlib1222add must be adjuster if you use a zlib version < 1.2.2.2 + +;uInt longest_match(s, cur_match) +; deflate_state *s; +; IPos cur_match; /* current match */ + + NbStack equ 76 + cur_match equ dword ptr[esp+NbStack-0] + str_s equ dword ptr[esp+NbStack-4] +; 5 dword on top (ret,ebp,esi,edi,ebx) + adrret equ dword ptr[esp+NbStack-8] + pushebp equ dword ptr[esp+NbStack-12] + pushedi equ dword ptr[esp+NbStack-16] + pushesi equ dword ptr[esp+NbStack-20] + pushebx equ dword ptr[esp+NbStack-24] + + chain_length equ dword ptr [esp+NbStack-28] + limit equ dword ptr [esp+NbStack-32] + best_len equ dword ptr [esp+NbStack-36] + window equ dword ptr [esp+NbStack-40] + prev equ dword ptr [esp+NbStack-44] + scan_start equ word ptr [esp+NbStack-48] + wmask equ dword ptr [esp+NbStack-52] + match_start_ptr equ dword ptr [esp+NbStack-56] + nice_match equ dword ptr [esp+NbStack-60] + scan equ dword ptr [esp+NbStack-64] + + windowlen equ dword ptr [esp+NbStack-68] + match_start equ dword ptr [esp+NbStack-72] + strend equ dword ptr [esp+NbStack-76] + NbStackAdd equ (NbStack-24) + + .386p + + name gvmatch + .MODEL FLAT + + + +; all the +zlib1222add offsets are due to the addition of fields +; in zlib in the deflate_state structure since the asm code was first written +; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)"). +; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0"). +; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8"). + + zlib1222add equ 8 + +; Note : these value are good with a 8 bytes boundary pack structure + dep_chain_length equ 74h+zlib1222add + dep_window equ 30h+zlib1222add + dep_strstart equ 64h+zlib1222add + dep_prev_length equ 70h+zlib1222add + dep_nice_match equ 88h+zlib1222add + dep_w_size equ 24h+zlib1222add + dep_prev equ 38h+zlib1222add + dep_w_mask equ 2ch+zlib1222add + dep_good_match equ 84h+zlib1222add + dep_match_start equ 68h+zlib1222add + dep_lookahead equ 6ch+zlib1222add + + +_TEXT segment + +IFDEF NOUNDERLINE + public longest_match + public match_init +ELSE + public _longest_match + public _match_init +ENDIF + + MAX_MATCH equ 258 + MIN_MATCH equ 3 + MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1) + + + +MAX_MATCH equ 258 +MIN_MATCH equ 3 +MIN_LOOKAHEAD equ (MAX_MATCH + MIN_MATCH + 1) +MAX_MATCH_8_ equ ((MAX_MATCH + 7) AND 0FFF0h) + + +;;; stack frame offsets + +chainlenwmask equ esp + 0 ; high word: current chain len + ; low word: s->wmask +window equ esp + 4 ; local copy of s->window +windowbestlen equ esp + 8 ; s->window + bestlen +scanstart equ esp + 16 ; first two bytes of string +scanend equ esp + 12 ; last two bytes of string +scanalign equ esp + 20 ; dword-misalignment of string +nicematch equ esp + 24 ; a good enough match size +bestlen equ esp + 28 ; size of best match so far +scan equ esp + 32 ; ptr to string wanting match + +LocalVarsSize equ 36 +; saved ebx byte esp + 36 +; saved edi byte esp + 40 +; saved esi byte esp + 44 +; saved ebp byte esp + 48 +; return address byte esp + 52 +deflatestate equ esp + 56 ; the function arguments +curmatch equ esp + 60 + +;;; Offsets for fields in the deflate_state structure. These numbers +;;; are calculated from the definition of deflate_state, with the +;;; assumption that the compiler will dword-align the fields. (Thus, +;;; changing the definition of deflate_state could easily cause this +;;; program to crash horribly, without so much as a warning at +;;; compile time. Sigh.) + +dsWSize equ 36+zlib1222add +dsWMask equ 44+zlib1222add +dsWindow equ 48+zlib1222add +dsPrev equ 56+zlib1222add +dsMatchLen equ 88+zlib1222add +dsPrevMatch equ 92+zlib1222add +dsStrStart equ 100+zlib1222add +dsMatchStart equ 104+zlib1222add +dsLookahead equ 108+zlib1222add +dsPrevLen equ 112+zlib1222add +dsMaxChainLen equ 116+zlib1222add +dsGoodMatch equ 132+zlib1222add +dsNiceMatch equ 136+zlib1222add + + +;;; match686.asm -- Pentium-Pro-optimized version of longest_match() +;;; Written for zlib 1.1.2 +;;; Copyright (C) 1998 Brian Raiter +;;; You can look at http://www.muppetlabs.com/~breadbox/software/assembly.html +;;; +;; +;; This software is provided 'as-is', without any express or implied +;; warranty. In no event will the authors be held liable for any damages +;; arising from the use of this software. +;; +;; Permission is granted to anyone to use this software for any purpose, +;; including commercial applications, and to alter it and redistribute it +;; freely, subject to the following restrictions: +;; +;; 1. The origin of this software must not be misrepresented; you must not +;; claim that you wrote the original software. If you use this software +;; in a product, an acknowledgment in the product documentation would be +;; appreciated but is not required. +;; 2. Altered source versions must be plainly marked as such, and must not be +;; misrepresented as being the original software +;; 3. This notice may not be removed or altered from any source distribution. +;; + +;GLOBAL _longest_match, _match_init + + +;SECTION .text + +;;; uInt longest_match(deflate_state *deflatestate, IPos curmatch) + +;_longest_match: + IFDEF NOUNDERLINE + longest_match proc near + ELSE + _longest_match proc near + ENDIF +.FPO (9, 4, 0, 0, 1, 0) + +;;; Save registers that the compiler may be using, and adjust esp to +;;; make room for our stack frame. + + push ebp + push edi + push esi + push ebx + sub esp, LocalVarsSize + +;;; Retrieve the function arguments. ecx will hold cur_match +;;; throughout the entire function. edx will hold the pointer to the +;;; deflate_state structure during the function's setup (before +;;; entering the main loop. + + mov edx, [deflatestate] + mov ecx, [curmatch] + +;;; uInt wmask = s->w_mask; +;;; unsigned chain_length = s->max_chain_length; +;;; if (s->prev_length >= s->good_match) { +;;; chain_length >>= 2; +;;; } + + mov eax, [edx + dsPrevLen] + mov ebx, [edx + dsGoodMatch] + cmp eax, ebx + mov eax, [edx + dsWMask] + mov ebx, [edx + dsMaxChainLen] + jl LastMatchGood + shr ebx, 2 +LastMatchGood: + +;;; chainlen is decremented once beforehand so that the function can +;;; use the sign flag instead of the zero flag for the exit test. +;;; It is then shifted into the high word, to make room for the wmask +;;; value, which it will always accompany. + + dec ebx + shl ebx, 16 + or ebx, eax + mov [chainlenwmask], ebx + +;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + mov eax, [edx + dsNiceMatch] + mov ebx, [edx + dsLookahead] + cmp ebx, eax + jl LookaheadLess + mov ebx, eax +LookaheadLess: mov [nicematch], ebx + +;;; register Bytef *scan = s->window + s->strstart; + + mov esi, [edx + dsWindow] + mov [window], esi + mov ebp, [edx + dsStrStart] + lea edi, [esi + ebp] + mov [scan], edi + +;;; Determine how many bytes the scan ptr is off from being +;;; dword-aligned. + + mov eax, edi + neg eax + and eax, 3 + mov [scanalign], eax + +;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ? +;;; s->strstart - (IPos)MAX_DIST(s) : NIL; + + mov eax, [edx + dsWSize] + sub eax, MIN_LOOKAHEAD + sub ebp, eax + jg LimitPositive + xor ebp, ebp +LimitPositive: + +;;; int best_len = s->prev_length; + + mov eax, [edx + dsPrevLen] + mov [bestlen], eax + +;;; Store the sum of s->window + best_len in esi locally, and in esi. + + add esi, eax + mov [windowbestlen], esi + +;;; register ush scan_start = *(ushf*)scan; +;;; register ush scan_end = *(ushf*)(scan+best_len-1); +;;; Posf *prev = s->prev; + + movzx ebx, word ptr [edi] + mov [scanstart], ebx + movzx ebx, word ptr [edi + eax - 1] + mov [scanend], ebx + mov edi, [edx + dsPrev] + +;;; Jump into the main loop. + + mov edx, [chainlenwmask] + jmp short LoopEntry + +align 4 + +;;; do { +;;; match = s->window + cur_match; +;;; if (*(ushf*)(match+best_len-1) != scan_end || +;;; *(ushf*)match != scan_start) continue; +;;; [...] +;;; } while ((cur_match = prev[cur_match & wmask]) > limit +;;; && --chain_length != 0); +;;; +;;; Here is the inner loop of the function. The function will spend the +;;; majority of its time in this loop, and majority of that time will +;;; be spent in the first ten instructions. +;;; +;;; Within this loop: +;;; ebx = scanend +;;; ecx = curmatch +;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask) +;;; esi = windowbestlen - i.e., (window + bestlen) +;;; edi = prev +;;; ebp = limit + +LookupLoop: + and ecx, edx + movzx ecx, word ptr [edi + ecx*2] + cmp ecx, ebp + jbe LeaveNow + sub edx, 00010000h + js LeaveNow +LoopEntry: movzx eax, word ptr [esi + ecx - 1] + cmp eax, ebx + jnz LookupLoop + mov eax, [window] + movzx eax, word ptr [eax + ecx] + cmp eax, [scanstart] + jnz LookupLoop + +;;; Store the current value of chainlen. + + mov [chainlenwmask], edx + +;;; Point edi to the string under scrutiny, and esi to the string we +;;; are hoping to match it up with. In actuality, esi and edi are +;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is +;;; initialized to -(MAX_MATCH_8 - scanalign). + + mov esi, [window] + mov edi, [scan] + add esi, ecx + mov eax, [scanalign] + mov edx, 0fffffef8h; -(MAX_MATCH_8) + lea edi, [edi + eax + 0108h] ;MAX_MATCH_8] + lea esi, [esi + eax + 0108h] ;MAX_MATCH_8] + +;;; Test the strings for equality, 8 bytes at a time. At the end, +;;; adjust edx so that it is offset to the exact byte that mismatched. +;;; +;;; We already know at this point that the first three bytes of the +;;; strings match each other, and they can be safely passed over before +;;; starting the compare loop. So what this code does is skip over 0-3 +;;; bytes, as much as necessary in order to dword-align the edi +;;; pointer. (esi will still be misaligned three times out of four.) +;;; +;;; It should be confessed that this loop usually does not represent +;;; much of the total running time. Replacing it with a more +;;; straightforward "rep cmpsb" would not drastically degrade +;;; performance. + +LoopCmps: + mov eax, [esi + edx] + xor eax, [edi + edx] + jnz LeaveLoopCmps + mov eax, [esi + edx + 4] + xor eax, [edi + edx + 4] + jnz LeaveLoopCmps4 + add edx, 8 + jnz LoopCmps + jmp short LenMaximum +LeaveLoopCmps4: add edx, 4 +LeaveLoopCmps: test eax, 0000FFFFh + jnz LenLower + add edx, 2 + shr eax, 16 +LenLower: sub al, 1 + adc edx, 0 + +;;; Calculate the length of the match. If it is longer than MAX_MATCH, +;;; then automatically accept it as the best possible match and leave. + + lea eax, [edi + edx] + mov edi, [scan] + sub eax, edi + cmp eax, MAX_MATCH + jge LenMaximum + +;;; If the length of the match is not longer than the best match we +;;; have so far, then forget it and return to the lookup loop. + + mov edx, [deflatestate] + mov ebx, [bestlen] + cmp eax, ebx + jg LongerMatch + mov esi, [windowbestlen] + mov edi, [edx + dsPrev] + mov ebx, [scanend] + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; s->match_start = cur_match; +;;; best_len = len; +;;; if (len >= nice_match) break; +;;; scan_end = *(ushf*)(scan+best_len-1); + +LongerMatch: mov ebx, [nicematch] + mov [bestlen], eax + mov [edx + dsMatchStart], ecx + cmp eax, ebx + jge LeaveNow + mov esi, [window] + add esi, eax + mov [windowbestlen], esi + movzx ebx, word ptr [edi + eax - 1] + mov edi, [edx + dsPrev] + mov [scanend], ebx + mov edx, [chainlenwmask] + jmp LookupLoop + +;;; Accept the current string, with the maximum possible length. + +LenMaximum: mov edx, [deflatestate] + mov dword ptr [bestlen], MAX_MATCH + mov [edx + dsMatchStart], ecx + +;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len; +;;; return s->lookahead; + +LeaveNow: + mov edx, [deflatestate] + mov ebx, [bestlen] + mov eax, [edx + dsLookahead] + cmp ebx, eax + jg LookaheadRet + mov eax, ebx +LookaheadRet: + +;;; Restore the stack and return from whence we came. + + add esp, LocalVarsSize + pop ebx + pop esi + pop edi + pop ebp + + ret +; please don't remove this string ! +; Your can freely use match686 in any free or commercial app if you don't remove the string in the binary! + db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998",0dh,0ah + + + IFDEF NOUNDERLINE + longest_match endp + ELSE + _longest_match endp + ENDIF + + IFDEF NOUNDERLINE + match_init proc near + ret + match_init endp + ELSE + _match_init proc near + ret + _match_init endp + ENDIF + + +_TEXT ends +end diff --git a/test/zlib/zlib-1.2.8/contrib/masmx86/readme.txt b/test/zlib/zlib-1.2.8/contrib/masmx86/readme.txt new file mode 100644 index 000000000..3f8888679 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/masmx86/readme.txt @@ -0,0 +1,27 @@ + +Summary +------- +This directory contains ASM implementations of the functions +longest_match() and inflate_fast(). + + +Use instructions +---------------- +Assemble using MASM, and copy the object files into the zlib source +directory, then run the appropriate makefile, as suggested below. You can +donwload MASM from here: + + http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=7a1c9da0-0510-44a2-b042-7ef370530c64 + +You can also get objects files here: + + http://www.winimage.com/zLibDll/zlib124_masm_obj.zip + +Build instructions +------------------ +* With Microsoft C and MASM: +nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" OBJA="match686.obj inffas32.obj" + +* With Borland C and TASM: +make -f win32/Makefile.bor LOCAL_ZLIB="-DASMV -DASMINF" OBJA="match686.obj inffas32.obj" OBJPA="+match686c.obj+match686.obj+inffas32.obj" + diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/Makefile b/test/zlib/zlib-1.2.8/contrib/minizip/Makefile new file mode 100644 index 000000000..84eaad20d --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/Makefile @@ -0,0 +1,25 @@ +CC=cc +CFLAGS=-O -I../.. + +UNZ_OBJS = miniunz.o unzip.o ioapi.o ../../libz.a +ZIP_OBJS = minizip.o zip.o ioapi.o ../../libz.a + +.c.o: + $(CC) -c $(CFLAGS) $*.c + +all: miniunz minizip + +miniunz: $(UNZ_OBJS) + $(CC) $(CFLAGS) -o $@ $(UNZ_OBJS) + +minizip: $(ZIP_OBJS) + $(CC) $(CFLAGS) -o $@ $(ZIP_OBJS) + +test: miniunz minizip + ./minizip test readme.txt + ./miniunz -l test.zip + mv readme.txt readme.old + ./miniunz test.zip + +clean: + /bin/rm -f *.o *~ minizip miniunz diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/Makefile.am b/test/zlib/zlib-1.2.8/contrib/minizip/Makefile.am new file mode 100644 index 000000000..d343011eb --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/Makefile.am @@ -0,0 +1,45 @@ +lib_LTLIBRARIES = libminizip.la + +if COND_DEMOS +bin_PROGRAMS = miniunzip minizip +endif + +zlib_top_srcdir = $(top_srcdir)/../.. +zlib_top_builddir = $(top_builddir)/../.. + +AM_CPPFLAGS = -I$(zlib_top_srcdir) +AM_LDFLAGS = -L$(zlib_top_builddir) + +if WIN32 +iowin32_src = iowin32.c +iowin32_h = iowin32.h +endif + +libminizip_la_SOURCES = \ + ioapi.c \ + mztools.c \ + unzip.c \ + zip.c \ + ${iowin32_src} + +libminizip_la_LDFLAGS = $(AM_LDFLAGS) -version-info 1:0:0 -lz + +minizip_includedir = $(includedir)/minizip +minizip_include_HEADERS = \ + crypt.h \ + ioapi.h \ + mztools.h \ + unzip.h \ + zip.h \ + ${iowin32_h} + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = minizip.pc + +EXTRA_PROGRAMS = miniunzip minizip + +miniunzip_SOURCES = miniunz.c +miniunzip_LDADD = libminizip.la + +minizip_SOURCES = minizip.c +minizip_LDADD = libminizip.la -lz diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/MiniZip64_Changes.txt b/test/zlib/zlib-1.2.8/contrib/minizip/MiniZip64_Changes.txt new file mode 100644 index 000000000..13a1bd91a --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/MiniZip64_Changes.txt @@ -0,0 +1,6 @@ + +MiniZip 1.1 was derrived from MiniZip at version 1.01f + +Change in 1.0 (Okt 2009) + - **TODO - Add history** + diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/MiniZip64_info.txt b/test/zlib/zlib-1.2.8/contrib/minizip/MiniZip64_info.txt new file mode 100644 index 000000000..57d715242 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/MiniZip64_info.txt @@ -0,0 +1,74 @@ +MiniZip - Copyright (c) 1998-2010 - by Gilles Vollant - version 1.1 64 bits from Mathias Svensson + +Introduction +--------------------- +MiniZip 1.1 is built from MiniZip 1.0 by Gilles Vollant ( http://www.winimage.com/zLibDll/minizip.html ) + +When adding ZIP64 support into minizip it would result into risk of breaking compatibility with minizip 1.0. +All possible work was done for compatibility. + + +Background +--------------------- +When adding ZIP64 support Mathias Svensson found that Even Rouault have added ZIP64 +support for unzip.c into minizip for a open source project called gdal ( http://www.gdal.org/ ) + +That was used as a starting point. And after that ZIP64 support was added to zip.c +some refactoring and code cleanup was also done. + + +Changed from MiniZip 1.0 to MiniZip 1.1 +--------------------------------------- +* Added ZIP64 support for unzip ( by Even Rouault ) +* Added ZIP64 support for zip ( by Mathias Svensson ) +* Reverted some changed that Even Rouault did. +* Bunch of patches received from Gulles Vollant that he received for MiniZip from various users. +* Added unzip patch for BZIP Compression method (patch create by Daniel Borca) +* Added BZIP Compress method for zip +* Did some refactoring and code cleanup + + +Credits + + Gilles Vollant - Original MiniZip author + Even Rouault - ZIP64 unzip Support + Daniel Borca - BZip Compression method support in unzip + Mathias Svensson - ZIP64 zip support + Mathias Svensson - BZip Compression method support in zip + + Resources + + ZipLayout http://result42.com/projects/ZipFileLayout + Command line tool for Windows that shows the layout and information of the headers in a zip archive. + Used when debugging and validating the creation of zip files using MiniZip64 + + + ZIP App Note http://www.pkware.com/documents/casestudies/APPNOTE.TXT + Zip File specification + + +Notes. + * To be able to use BZip compression method in zip64.c or unzip64.c the BZIP2 lib is needed and HAVE_BZIP2 need to be defined. + +License +---------------------------------------------------------- + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + +---------------------------------------------------------- + diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/configure.ac b/test/zlib/zlib-1.2.8/contrib/minizip/configure.ac new file mode 100644 index 000000000..827a4e057 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/configure.ac @@ -0,0 +1,32 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +AC_INIT([minizip], [1.2.8], [bugzilla.redhat.com]) +AC_CONFIG_SRCDIR([minizip.c]) +AM_INIT_AUTOMAKE([foreign]) +LT_INIT + +AC_MSG_CHECKING([whether to build example programs]) +AC_ARG_ENABLE([demos], AC_HELP_STRING([--enable-demos], [build example programs])) +AM_CONDITIONAL([COND_DEMOS], [test "$enable_demos" = yes]) +if test "$enable_demos" = yes +then + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +case "${host}" in + *-mingw* | mingw*) + WIN32="yes" + ;; + *) + ;; +esac +AM_CONDITIONAL([WIN32], [test "${WIN32}" = "yes"]) + + +AC_SUBST([HAVE_UNISTD_H], [0]) +AC_CHECK_HEADER([unistd.h], [HAVE_UNISTD_H=1], []) +AC_CONFIG_FILES([Makefile minizip.pc]) +AC_OUTPUT diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/crypt.h b/test/zlib/zlib-1.2.8/contrib/minizip/crypt.h new file mode 100644 index 000000000..1e9e8200b --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/crypt.h @@ -0,0 +1,131 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const z_crc_t* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(const char* passwd, /* password string */ + unsigned char* buf, /* where to write header */ + int bufSize, + unsigned long* pkeys, + const z_crc_t* pcrc_32_tab, + unsigned long crcForCrypting) +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/ioapi.c b/test/zlib/zlib-1.2.8/contrib/minizip/ioapi.c new file mode 100644 index 000000000..7f5c191b2 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/ioapi.c @@ -0,0 +1,247 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS))) + #define _CRT_SECURE_NO_WARNINGS +#endif + +#if defined(__APPLE__) || defined(IOAPI_NO_64) +// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions +#define FOPEN_FUNC(filename, mode) fopen(filename, mode) +#define FTELLO_FUNC(stream) ftello(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) +#else +#define FOPEN_FUNC(filename, mode) fopen64(filename, mode) +#define FTELLO_FUNC(stream) ftello64(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) +#endif + + +#include "ioapi.h" + +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) +{ + if (pfilefunc->zfile_func64.zopen64_file != NULL) + return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); + else + { + return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); + } +} + +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); + else + { + uLong offsetTruncated = (uLong)offset; + if (offsetTruncated != offset) + return -1; + else + return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); + } +} + +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); + else + { + uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); + if ((tell_uLong) == MAXU32) + return (ZPOS64_T)-1; + else + return tell_uLong; + } +} + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) +{ + p_filefunc64_32->zfile_func64.zopen64_file = NULL; + p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; + p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; + p_filefunc64_32->zfile_func64.ztell64_file = NULL; + p_filefunc64_32->zfile_func64.zseek64_file = NULL; + p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; + p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; + p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; +} + + + +static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); +static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); +static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); +static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); +static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); + +static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + +static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = FOPEN_FUNC((const char*)filename, mode_fopen); + return file; +} + + +static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + + +static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret; + ret = FTELLO_FUNC((FILE *)stream); + return ret; +} + +static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + if (fseek((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + return ret; +} + +static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + + if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + + return ret; +} + + +static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = fopen64_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell64_file = ftell64_file_func; + pzlib_filefunc_def->zseek64_file = fseek64_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/ioapi.h b/test/zlib/zlib-1.2.8/contrib/minizip/ioapi.h new file mode 100644 index 000000000..8dcbdb06e --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/ioapi.h @@ -0,0 +1,208 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + + Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) + Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. + More if/def section may be needed to support other platforms + Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. + (but you should use iowin32.c for windows instead) + +*/ + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) + + // Linux needs this to support file operation on files larger then 4+GB + // But might need better if/def to select just the platforms that needs them. + + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif + +#endif + +#include +#include +#include "zlib.h" + +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef __FreeBSD__ +#define fopen64 fopen +#define ftello64 ftello +#define fseeko64 fseeko +#endif +#ifdef _MSC_VER + #define fopen64 fopen + #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) + #define ftello64 _ftelli64 + #define fseeko64 _fseeki64 + #else // old MSC + #define ftello64 ftell + #define fseeko64 fseek + #endif +#endif +#endif + +/* +#ifndef ZPOS64_T + #ifdef _WIN32 + #define ZPOS64_T fpos_t + #else + #include + #define ZPOS64_T uint64_t + #endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + +/* Maximum unsigned 32-bit value used as placeholder for zip64 */ +#define MAXU32 0xffffffff + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) + #define ZCALLBACK CALLBACK + #else + #define ZCALLBACK + #endif +#endif + + + + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) +//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/iowin32.c b/test/zlib/zlib-1.2.8/contrib/minizip/iowin32.c new file mode 100644 index 000000000..a46d96c7f --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/iowin32.c @@ -0,0 +1,461 @@ +/* iowin32.c -- IO base function header for compress/uncompress .zip + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#include + +#include "zlib.h" +#include "ioapi.h" +#include "iowin32.h" + +#ifndef INVALID_HANDLE_VALUE +#define INVALID_HANDLE_VALUE (0xFFFFFFFF) +#endif + +#ifndef INVALID_SET_FILE_POINTER +#define INVALID_SET_FILE_POINTER ((DWORD)-1) +#endif + + +#if defined(WINAPI_FAMILY_PARTITION) && (!(defined(IOWIN32_USING_WINRT_API))) +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +#define IOWIN32_USING_WINRT_API 1 +#endif +#endif + +voidpf ZCALLBACK win32_open_file_func OF((voidpf opaque, const char* filename, int mode)); +uLong ZCALLBACK win32_read_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +uLong ZCALLBACK win32_write_file_func OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +ZPOS64_T ZCALLBACK win32_tell64_file_func OF((voidpf opaque, voidpf stream)); +long ZCALLBACK win32_seek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +int ZCALLBACK win32_close_file_func OF((voidpf opaque, voidpf stream)); +int ZCALLBACK win32_error_file_func OF((voidpf opaque, voidpf stream)); + +typedef struct +{ + HANDLE hf; + int error; +} WIN32FILE_IOWIN; + + +static void win32_translate_open_mode(int mode, + DWORD* lpdwDesiredAccess, + DWORD* lpdwCreationDisposition, + DWORD* lpdwShareMode, + DWORD* lpdwFlagsAndAttributes) +{ + *lpdwDesiredAccess = *lpdwShareMode = *lpdwFlagsAndAttributes = *lpdwCreationDisposition = 0; + + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + { + *lpdwDesiredAccess = GENERIC_READ; + *lpdwCreationDisposition = OPEN_EXISTING; + *lpdwShareMode = FILE_SHARE_READ; + } + else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + { + *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + *lpdwCreationDisposition = OPEN_EXISTING; + } + else if (mode & ZLIB_FILEFUNC_MODE_CREATE) + { + *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ; + *lpdwCreationDisposition = CREATE_ALWAYS; + } +} + +static voidpf win32_build_iowin(HANDLE hFile) +{ + voidpf ret=NULL; + + if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)) + { + WIN32FILE_IOWIN w32fiow; + w32fiow.hf = hFile; + w32fiow.error = 0; + ret = malloc(sizeof(WIN32FILE_IOWIN)); + + if (ret==NULL) + CloseHandle(hFile); + else + *((WIN32FILE_IOWIN*)ret) = w32fiow; + } + return ret; +} + +voidpf ZCALLBACK win32_open64_file_func (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + +#ifdef IOWIN32_USING_WINRT_API +#ifdef UNICODE + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile2((LPCTSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + { + WCHAR filenameW[FILENAME_MAX + 0x200 + 1]; + MultiByteToWideChar(CP_ACP,0,(const char*)filename,-1,filenameW,FILENAME_MAX + 0x200); + hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); + } +#endif +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); +#endif + + return win32_build_iowin(hFile); +} + + +voidpf ZCALLBACK win32_open64_file_funcA (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + +#ifdef IOWIN32_USING_WINRT_API + if ((filename!=NULL) && (dwDesiredAccess != 0)) + { + WCHAR filenameW[FILENAME_MAX + 0x200 + 1]; + MultiByteToWideChar(CP_ACP,0,(const char*)filename,-1,filenameW,FILENAME_MAX + 0x200); + hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); + } +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFileA((LPCSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); +#endif + + return win32_build_iowin(hFile); +} + + +voidpf ZCALLBACK win32_open64_file_funcW (voidpf opaque,const void* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + +#ifdef IOWIN32_USING_WINRT_API + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile2((LPCWSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition,NULL); +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFileW((LPCWSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); +#endif + + return win32_build_iowin(hFile); +} + + +voidpf ZCALLBACK win32_open_file_func (voidpf opaque,const char* filename,int mode) +{ + const char* mode_fopen = NULL; + DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ; + HANDLE hFile = NULL; + + win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes); + +#ifdef IOWIN32_USING_WINRT_API +#ifdef UNICODE + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile2((LPCTSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + { + WCHAR filenameW[FILENAME_MAX + 0x200 + 1]; + MultiByteToWideChar(CP_ACP,0,(const char*)filename,-1,filenameW,FILENAME_MAX + 0x200); + hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL); + } +#endif +#else + if ((filename!=NULL) && (dwDesiredAccess != 0)) + hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL); +#endif + + return win32_build_iowin(hFile); +} + + +uLong ZCALLBACK win32_read_file_func (voidpf opaque, voidpf stream, void* buf,uLong size) +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + + if (hFile != NULL) + { + if (!ReadFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + } + + return ret; +} + + +uLong ZCALLBACK win32_write_file_func (voidpf opaque,voidpf stream,const void* buf,uLong size) +{ + uLong ret=0; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + + if (hFile != NULL) + { + if (!WriteFile(hFile, buf, size, &ret, NULL)) + { + DWORD dwErr = GetLastError(); + if (dwErr == ERROR_HANDLE_EOF) + dwErr = 0; + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + } + } + + return ret; +} + +static BOOL MySetFilePointerEx(HANDLE hFile, LARGE_INTEGER pos, LARGE_INTEGER *newPos, DWORD dwMoveMethod) +{ +#ifdef IOWIN32_USING_WINRT_API + return SetFilePointerEx(hFile, pos, newPos, dwMoveMethod); +#else + LONG lHigh = pos.HighPart; + DWORD dwNewPos = SetFilePointer(hFile, pos.LowPart, &lHigh, FILE_CURRENT); + BOOL fOk = TRUE; + if (dwNewPos == 0xFFFFFFFF) + if (GetLastError() != NO_ERROR) + fOk = FALSE; + if ((newPos != NULL) && (fOk)) + { + newPos->LowPart = dwNewPos; + newPos->HighPart = lHigh; + } + return fOk; +#endif +} + +long ZCALLBACK win32_tell_file_func (voidpf opaque,voidpf stream) +{ + long ret=-1; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + LARGE_INTEGER pos; + pos.QuadPart = 0; + + if (!MySetFilePointerEx(hFile, pos, &pos, FILE_CURRENT)) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=(long)pos.LowPart; + } + return ret; +} + +ZPOS64_T ZCALLBACK win32_tell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret= (ZPOS64_T)-1; + HANDLE hFile = NULL; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream)->hf; + + if (hFile) + { + LARGE_INTEGER pos; + pos.QuadPart = 0; + + if (!MySetFilePointerEx(hFile, pos, &pos, FILE_CURRENT)) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = (ZPOS64_T)-1; + } + else + ret=pos.QuadPart; + } + return ret; +} + + +long ZCALLBACK win32_seek_file_func (voidpf opaque,voidpf stream,uLong offset,int origin) +{ + DWORD dwMoveMethod=0xFFFFFFFF; + HANDLE hFile = NULL; + + long ret=-1; + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + dwMoveMethod = FILE_CURRENT; + break; + case ZLIB_FILEFUNC_SEEK_END : + dwMoveMethod = FILE_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + dwMoveMethod = FILE_BEGIN; + break; + default: return -1; + } + + if (hFile != NULL) + { + LARGE_INTEGER pos; + pos.QuadPart = offset; + if (!MySetFilePointerEx(hFile, pos, NULL, dwMoveMethod)) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=0; + } + return ret; +} + +long ZCALLBACK win32_seek64_file_func (voidpf opaque, voidpf stream,ZPOS64_T offset,int origin) +{ + DWORD dwMoveMethod=0xFFFFFFFF; + HANDLE hFile = NULL; + long ret=-1; + + if (stream!=NULL) + hFile = ((WIN32FILE_IOWIN*)stream)->hf; + + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + dwMoveMethod = FILE_CURRENT; + break; + case ZLIB_FILEFUNC_SEEK_END : + dwMoveMethod = FILE_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + dwMoveMethod = FILE_BEGIN; + break; + default: return -1; + } + + if (hFile) + { + LARGE_INTEGER pos; + pos.QuadPart = offset; + if (!MySetFilePointerEx(hFile, pos, NULL, FILE_CURRENT)) + { + DWORD dwErr = GetLastError(); + ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr; + ret = -1; + } + else + ret=0; + } + return ret; +} + +int ZCALLBACK win32_close_file_func (voidpf opaque, voidpf stream) +{ + int ret=-1; + + if (stream!=NULL) + { + HANDLE hFile; + hFile = ((WIN32FILE_IOWIN*)stream) -> hf; + if (hFile != NULL) + { + CloseHandle(hFile); + ret=0; + } + free(stream); + } + return ret; +} + +int ZCALLBACK win32_error_file_func (voidpf opaque,voidpf stream) +{ + int ret=-1; + if (stream!=NULL) + { + ret = ((WIN32FILE_IOWIN*)stream) -> error; + } + return ret; +} + +void fill_win32_filefunc (zlib_filefunc_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen_file = win32_open_file_func; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell_file = win32_tell_file_func; + pzlib_filefunc_def->zseek_file = win32_seek_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_win32_filefunc64(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_func; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + + +void fill_win32_filefunc64A(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_funcA; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} + + +void fill_win32_filefunc64W(zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = win32_open64_file_funcW; + pzlib_filefunc_def->zread_file = win32_read_file_func; + pzlib_filefunc_def->zwrite_file = win32_write_file_func; + pzlib_filefunc_def->ztell64_file = win32_tell64_file_func; + pzlib_filefunc_def->zseek64_file = win32_seek64_file_func; + pzlib_filefunc_def->zclose_file = win32_close_file_func; + pzlib_filefunc_def->zerror_file = win32_error_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/iowin32.h b/test/zlib/zlib-1.2.8/contrib/minizip/iowin32.h new file mode 100644 index 000000000..0ca0969a7 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/iowin32.h @@ -0,0 +1,28 @@ +/* iowin32.h -- IO base function header for compress/uncompress .zip + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); +void fill_win32_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64A OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_win32_filefunc64W OF((zlib_filefunc64_def* pzlib_filefunc_def)); + +#ifdef __cplusplus +} +#endif diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/make_vms.com b/test/zlib/zlib-1.2.8/contrib/minizip/make_vms.com new file mode 100644 index 000000000..9ac13a98f --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/make_vms.com @@ -0,0 +1,25 @@ +$ if f$search("ioapi.h_orig") .eqs. "" then copy ioapi.h ioapi.h_orig +$ open/write zdef vmsdefs.h +$ copy sys$input: zdef +$ deck +#define unix +#define fill_zlib_filefunc64_32_def_from_filefunc32 fillzffunc64from +#define Write_Zip64EndOfCentralDirectoryLocator Write_Zip64EoDLocator +#define Write_Zip64EndOfCentralDirectoryRecord Write_Zip64EoDRecord +#define Write_EndOfCentralDirectoryRecord Write_EoDRecord +$ eod +$ close zdef +$ copy vmsdefs.h,ioapi.h_orig ioapi.h +$ cc/include=[--]/prefix=all ioapi.c +$ cc/include=[--]/prefix=all miniunz.c +$ cc/include=[--]/prefix=all unzip.c +$ cc/include=[--]/prefix=all minizip.c +$ cc/include=[--]/prefix=all zip.c +$ link miniunz,unzip,ioapi,[--]libz.olb/lib +$ link minizip,zip,ioapi,[--]libz.olb/lib +$ mcr []minizip test minizip_info.txt +$ mcr []miniunz -l test.zip +$ rename minizip_info.txt; minizip_info.txt_old +$ mcr []miniunz test.zip +$ delete test.zip;* +$exit diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/miniunz.c b/test/zlib/zlib-1.2.8/contrib/minizip/miniunz.c new file mode 100644 index 000000000..3d65401be --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/miniunz.c @@ -0,0 +1,660 @@ +/* + miniunz.c + Version 1.1, February 14h, 2010 + sample part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) +*/ + +#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#ifdef __APPLE__ +// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions +#define FOPEN_FUNC(filename, mode) fopen(filename, mode) +#define FTELLO_FUNC(stream) ftello(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) +#else +#define FOPEN_FUNC(filename, mode) fopen64(filename, mode) +#define FTELLO_FUNC(stream) ftello64(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) +#endif + + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# include +# include +#else +# include +# include +#endif + + +#include "unzip.h" + +#define CASESENSITIVITY (0) +#define WRITEBUFFERSIZE (8192) +#define MAXFILENAME (256) + +#ifdef _WIN32 +#define USEWIN32IOAPI +#include "iowin32.h" +#endif +/* + mini unzip, demo of unzip package + + usage : + Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir] + + list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT + if it exists +*/ + + +/* change_file_date : change the date/time of a file + filename : the filename of the file where date/time must be modified + dosdate : the new date at the MSDos format (4 bytes) + tmu_date : the SAME new date at the tm_unz format */ +void change_file_date(filename,dosdate,tmu_date) + const char *filename; + uLong dosdate; + tm_unz tmu_date; +{ +#ifdef _WIN32 + HANDLE hFile; + FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite; + + hFile = CreateFileA(filename,GENERIC_READ | GENERIC_WRITE, + 0,NULL,OPEN_EXISTING,0,NULL); + GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite); + DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal); + LocalFileTimeToFileTime(&ftLocal,&ftm); + SetFileTime(hFile,&ftm,&ftLastAcc,&ftm); + CloseHandle(hFile); +#else +#ifdef unix || __APPLE__ + struct utimbuf ut; + struct tm newdate; + newdate.tm_sec = tmu_date.tm_sec; + newdate.tm_min=tmu_date.tm_min; + newdate.tm_hour=tmu_date.tm_hour; + newdate.tm_mday=tmu_date.tm_mday; + newdate.tm_mon=tmu_date.tm_mon; + if (tmu_date.tm_year > 1900) + newdate.tm_year=tmu_date.tm_year - 1900; + else + newdate.tm_year=tmu_date.tm_year ; + newdate.tm_isdst=-1; + + ut.actime=ut.modtime=mktime(&newdate); + utime(filename,&ut); +#endif +#endif +} + + +/* mymkdir and change_file_date are not 100 % portable + As I don't know well Unix, I wait feedback for the unix portion */ + +int mymkdir(dirname) + const char* dirname; +{ + int ret=0; +#ifdef _WIN32 + ret = _mkdir(dirname); +#elif unix + ret = mkdir (dirname,0775); +#elif __APPLE__ + ret = mkdir (dirname,0775); +#endif + return ret; +} + +int makedir (newdir) + char *newdir; +{ + char *buffer ; + char *p; + int len = (int)strlen(newdir); + + if (len <= 0) + return 0; + + buffer = (char*)malloc(len+1); + if (buffer==NULL) + { + printf("Error allocating memory\n"); + return UNZ_INTERNALERROR; + } + strcpy(buffer,newdir); + + if (buffer[len-1] == '/') { + buffer[len-1] = '\0'; + } + if (mymkdir(buffer) == 0) + { + free(buffer); + return 1; + } + + p = buffer+1; + while (1) + { + char hold; + + while(*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mymkdir(buffer) == -1) && (errno == ENOENT)) + { + printf("couldn't create directory %s\n",buffer); + free(buffer); + return 0; + } + if (hold == 0) + break; + *p++ = hold; + } + free(buffer); + return 1; +} + +void do_banner() +{ + printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n"); + printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n"); +} + +void do_help() +{ + printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \ + " -e Extract without pathname (junk paths)\n" \ + " -x Extract with pathname\n" \ + " -v list files\n" \ + " -l list files\n" \ + " -d directory to extract into\n" \ + " -o overwrite files without prompting\n" \ + " -p extract crypted file using password\n\n"); +} + +void Display64BitsSize(ZPOS64_T n, int size_char) +{ + /* to avoid compatibility problem , we do here the conversion */ + char number[21]; + int offset=19; + int pos_string = 19; + number[20]=0; + for (;;) { + number[offset]=(char)((n%10)+'0'); + if (number[offset] != '0') + pos_string=offset; + n/=10; + if (offset==0) + break; + offset--; + } + { + int size_display_string = 19-pos_string; + while (size_char > size_display_string) + { + size_char--; + printf(" "); + } + } + + printf("%s",&number[pos_string]); +} + +int do_list(uf) + unzFile uf; +{ + uLong i; + unz_global_info64 gi; + int err; + + err = unzGetGlobalInfo64(uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + printf(" Length Method Size Ratio Date Time CRC-32 Name\n"); + printf(" ------ ------ ---- ----- ---- ---- ------ ----\n"); + for (i=0;i0) + ratio = (uLong)((file_info.compressed_size*100)/file_info.uncompressed_size); + + /* display a '*' if the file is crypted */ + if ((file_info.flag & 1) != 0) + charCrypt='*'; + + if (file_info.compression_method==0) + string_method="Stored"; + else + if (file_info.compression_method==Z_DEFLATED) + { + uInt iLevel=(uInt)((file_info.flag & 0x6)/2); + if (iLevel==0) + string_method="Defl:N"; + else if (iLevel==1) + string_method="Defl:X"; + else if ((iLevel==2) || (iLevel==3)) + string_method="Defl:F"; /* 2:fast , 3 : extra fast*/ + } + else + if (file_info.compression_method==Z_BZIP2ED) + { + string_method="BZip2 "; + } + else + string_method="Unkn. "; + + Display64BitsSize(file_info.uncompressed_size,7); + printf(" %6s%c",string_method,charCrypt); + Display64BitsSize(file_info.compressed_size,7); + printf(" %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n", + ratio, + (uLong)file_info.tmu_date.tm_mon + 1, + (uLong)file_info.tmu_date.tm_mday, + (uLong)file_info.tmu_date.tm_year % 100, + (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min, + (uLong)file_info.crc,filename_inzip); + if ((i+1)='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + } + + if (rep == 'N') + skip = 1; + + if (rep == 'A') + *popt_overwrite=1; + } + + if ((skip==0) && (err==UNZ_OK)) + { + fout=FOPEN_FUNC(write_filename,"wb"); + /* some zipfile don't contain directory alone before file */ + if ((fout==NULL) && ((*popt_extract_without_path)==0) && + (filename_withoutpath!=(char*)filename_inzip)) + { + char c=*(filename_withoutpath-1); + *(filename_withoutpath-1)='\0'; + makedir(write_filename); + *(filename_withoutpath-1)=c; + fout=FOPEN_FUNC(write_filename,"wb"); + } + + if (fout==NULL) + { + printf("error opening %s\n",write_filename); + } + } + + if (fout!=NULL) + { + printf(" extracting: %s\n",write_filename); + + do + { + err = unzReadCurrentFile(uf,buf,size_buf); + if (err<0) + { + printf("error %d with zipfile in unzReadCurrentFile\n",err); + break; + } + if (err>0) + if (fwrite(buf,err,1,fout)!=1) + { + printf("error in writing extracted file\n"); + err=UNZ_ERRNO; + break; + } + } + while (err>0); + if (fout) + fclose(fout); + + if (err==0) + change_file_date(write_filename,file_info.dosDate, + file_info.tmu_date); + } + + if (err==UNZ_OK) + { + err = unzCloseCurrentFile (uf); + if (err!=UNZ_OK) + { + printf("error %d with zipfile in unzCloseCurrentFile\n",err); + } + } + else + unzCloseCurrentFile(uf); /* don't lose the error */ + } + + free(buf); + return err; +} + + +int do_extract(uf,opt_extract_without_path,opt_overwrite,password) + unzFile uf; + int opt_extract_without_path; + int opt_overwrite; + const char* password; +{ + uLong i; + unz_global_info64 gi; + int err; + FILE* fout=NULL; + + err = unzGetGlobalInfo64(uf,&gi); + if (err!=UNZ_OK) + printf("error %d with zipfile in unzGetGlobalInfo \n",err); + + for (i=0;i insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +miniunzip - uncompress and examine ZIP archives +.SH SYNOPSIS +.B miniunzip +.RI [ -exvlo ] +zipfile [ files_to_extract ] [-d tempdir] +.SH DESCRIPTION +.B minizip +is a simple tool which allows the extraction of compressed file +archives in the ZIP format used by the MS-DOS utility PKZIP. It was +written as a demonstration of the +.IR zlib (3) +library and therefore lack many of the features of the +.IR unzip (1) +program. +.SH OPTIONS +A number of options are supported. With the exception of +.BI \-d\ tempdir +these must be supplied before any +other arguments and are: +.TP +.BI \-l\ ,\ \-\-v +List the files in the archive without extracting them. +.TP +.B \-o +Overwrite files without prompting for confirmation. +.TP +.B \-x +Extract files (default). +.PP +The +.I zipfile +argument is the name of the archive to process. The next argument can be used +to specify a single file to extract from the archive. + +Lastly, the following option can be specified at the end of the command-line: +.TP +.BI \-d\ tempdir +Extract the archive in the directory +.I tempdir +rather than the current directory. +.SH SEE ALSO +.BR minizip (1), +.BR zlib (3), +.BR unzip (1). +.SH AUTHOR +This program was written by Gilles Vollant. This manual page was +written by Mark Brown . The -d tempdir option +was added by Dirk Eddelbuettel . diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/minizip.1 b/test/zlib/zlib-1.2.8/contrib/minizip/minizip.1 new file mode 100644 index 000000000..1154484c1 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/minizip.1 @@ -0,0 +1,46 @@ +.\" Hey, EMACS: -*- nroff -*- +.TH minizip 1 "May 2, 2001" +.\" Please adjust this date whenever revising the manpage. +.\" +.\" Some roff macros, for reference: +.\" .nh disable hyphenation +.\" .hy enable hyphenation +.\" .ad l left justify +.\" .ad b justify to both left and right margins +.\" .nf disable filling +.\" .fi enable filling +.\" .br insert line break +.\" .sp insert n+1 empty lines +.\" for manpage-specific macros, see man(7) +.SH NAME +minizip - create ZIP archives +.SH SYNOPSIS +.B minizip +.RI [ -o ] +zipfile [ " files" ... ] +.SH DESCRIPTION +.B minizip +is a simple tool which allows the creation of compressed file archives +in the ZIP format used by the MS-DOS utility PKZIP. It was written as +a demonstration of the +.IR zlib (3) +library and therefore lack many of the features of the +.IR zip (1) +program. +.SH OPTIONS +The first argument supplied is the name of the ZIP archive to create or +.RI -o +in which case it is ignored and the second argument treated as the +name of the ZIP file. If the ZIP file already exists it will be +overwritten. +.PP +Subsequent arguments specify a list of files to place in the ZIP +archive. If none are specified then an empty archive will be created. +.SH SEE ALSO +.BR miniunzip (1), +.BR zlib (3), +.BR zip (1). +.SH AUTHOR +This program was written by Gilles Vollant. This manual page was +written by Mark Brown . + diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/minizip.c b/test/zlib/zlib-1.2.8/contrib/minizip/minizip.c new file mode 100644 index 000000000..4288962ec --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/minizip.c @@ -0,0 +1,520 @@ +/* + minizip.c + Version 1.1, February 14h, 2010 + sample part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) +*/ + + +#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__)) + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#ifdef __APPLE__ +// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions +#define FOPEN_FUNC(filename, mode) fopen(filename, mode) +#define FTELLO_FUNC(stream) ftello(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin) +#else +#define FOPEN_FUNC(filename, mode) fopen64(filename, mode) +#define FTELLO_FUNC(stream) ftello64(stream) +#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin) +#endif + + + +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# include +# include +#else +# include +# include +# include +# include +#endif + +#include "zip.h" + +#ifdef _WIN32 + #define USEWIN32IOAPI + #include "iowin32.h" +#endif + + + +#define WRITEBUFFERSIZE (16384) +#define MAXFILENAME (256) + +#ifdef _WIN32 +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret = 0; + { + FILETIME ftLocal; + HANDLE hFind; + WIN32_FIND_DATAA ff32; + + hFind = FindFirstFileA(f,&ff32); + if (hFind != INVALID_HANDLE_VALUE) + { + FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); + FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); + FindClose(hFind); + ret = 1; + } + } + return ret; +} +#else +#ifdef unix || __APPLE__ +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + int ret=0; + struct stat s; /* results of stat() */ + struct tm* filedate; + time_t tm_t=0; + + if (strcmp(f,"-")!=0) + { + char name[MAXFILENAME+1]; + int len = strlen(f); + if (len > MAXFILENAME) + len = MAXFILENAME; + + strncpy(name, f,MAXFILENAME-1); + /* strncpy doesnt append the trailing NULL, of the string is too long. */ + name[ MAXFILENAME ] = '\0'; + + if (name[len - 1] == '/') + name[len - 1] = '\0'; + /* not all systems allow stat'ing a file with / appended */ + if (stat(name,&s)==0) + { + tm_t = s.st_mtime; + ret = 1; + } + } + filedate = localtime(&tm_t); + + tmzip->tm_sec = filedate->tm_sec; + tmzip->tm_min = filedate->tm_min; + tmzip->tm_hour = filedate->tm_hour; + tmzip->tm_mday = filedate->tm_mday; + tmzip->tm_mon = filedate->tm_mon ; + tmzip->tm_year = filedate->tm_year; + + return ret; +} +#else +uLong filetime(f, tmzip, dt) + char *f; /* name of file to get info on */ + tm_zip *tmzip; /* return value: access, modific. and creation times */ + uLong *dt; /* dostime */ +{ + return 0; +} +#endif +#endif + + + + +int check_exist_file(filename) + const char* filename; +{ + FILE* ftestexist; + int ret = 1; + ftestexist = FOPEN_FUNC(filename,"rb"); + if (ftestexist==NULL) + ret = 0; + else + fclose(ftestexist); + return ret; +} + +void do_banner() +{ + printf("MiniZip 1.1, demo of zLib + MiniZip64 package, written by Gilles Vollant\n"); + printf("more info on MiniZip at http://www.winimage.com/zLibDll/minizip.html\n\n"); +} + +void do_help() +{ + printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \ + " -o Overwrite existing file.zip\n" \ + " -a Append to existing file.zip\n" \ + " -0 Store only\n" \ + " -1 Compress faster\n" \ + " -9 Compress better\n\n" \ + " -j exclude path. store only the file name.\n\n"); +} + +/* calculate the CRC32 of a file, + because to encrypt a file, we need known the CRC32 of the file before */ +int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc) +{ + unsigned long calculate_crc=0; + int err=ZIP_OK; + FILE * fin = FOPEN_FUNC(filenameinzip,"rb"); + + unsigned long size_read = 0; + unsigned long total_read = 0; + if (fin==NULL) + { + err = ZIP_ERRNO; + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + calculate_crc = crc32(calculate_crc,buf,size_read); + total_read += size_read; + + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + *result_crc=calculate_crc; + printf("file %s crc %lx\n", filenameinzip, calculate_crc); + return err; +} + +int isLargeFile(const char* filename) +{ + int largeFile = 0; + ZPOS64_T pos = 0; + FILE* pFile = FOPEN_FUNC(filename, "rb"); + + if(pFile != NULL) + { + int n = FSEEKO_FUNC(pFile, 0, SEEK_END); + pos = FTELLO_FUNC(pFile); + + printf("File : %s is %lld bytes\n", filename, pos); + + if(pos >= 0xffffffff) + largeFile = 1; + + fclose(pFile); + } + + return largeFile; +} + +int main(argc,argv) + int argc; + char *argv[]; +{ + int i; + int opt_overwrite=0; + int opt_compress_level=Z_DEFAULT_COMPRESSION; + int opt_exclude_path=0; + int zipfilenamearg = 0; + char filename_try[MAXFILENAME+16]; + int zipok; + int err=0; + int size_buf=0; + void* buf=NULL; + const char* password=NULL; + + + do_banner(); + if (argc==1) + { + do_help(); + return 0; + } + else + { + for (i=1;i='0') && (c<='9')) + opt_compress_level = c-'0'; + if ((c=='j') || (c=='J')) + opt_exclude_path = 1; + + if (((c=='p') || (c=='P')) && (i+1='a') && (rep<='z')) + rep -= 0x20; + } + while ((rep!='Y') && (rep!='N') && (rep!='A')); + if (rep=='N') + zipok = 0; + if (rep=='A') + opt_overwrite = 2; + } + } + + if (zipok==1) + { + zipFile zf; + int errclose; +# ifdef USEWIN32IOAPI + zlib_filefunc64_def ffunc; + fill_win32_filefunc64A(&ffunc); + zf = zipOpen2_64(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc); +# else + zf = zipOpen64(filename_try,(opt_overwrite==2) ? 2 : 0); +# endif + + if (zf == NULL) + { + printf("error opening %s\n",filename_try); + err= ZIP_ERRNO; + } + else + printf("creating %s\n",filename_try); + + for (i=zipfilenamearg+1;(i='0') || (argv[i][1]<='9'))) && + (strlen(argv[i]) == 2))) + { + FILE * fin; + int size_read; + const char* filenameinzip = argv[i]; + const char *savefilenameinzip; + zip_fileinfo zi; + unsigned long crcFile=0; + int zip64 = 0; + + zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour = + zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0; + zi.dosDate = 0; + zi.internal_fa = 0; + zi.external_fa = 0; + filetime(filenameinzip,&zi.tmz_date,&zi.dosDate); + +/* + err = zipOpenNewFileInZip(zf,filenameinzip,&zi, + NULL,0,NULL,0,NULL / * comment * /, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level); +*/ + if ((password != NULL) && (err==ZIP_OK)) + err = getFileCrc(filenameinzip,buf,size_buf,&crcFile); + + zip64 = isLargeFile(filenameinzip); + + /* The path name saved, should not include a leading slash. */ + /*if it did, windows/xp and dynazip couldn't read the zip file. */ + savefilenameinzip = filenameinzip; + while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' ) + { + savefilenameinzip++; + } + + /*should the zip file contain any path at all?*/ + if( opt_exclude_path ) + { + const char *tmpptr; + const char *lastslash = 0; + for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++) + { + if( *tmpptr == '\\' || *tmpptr == '/') + { + lastslash = tmpptr; + } + } + if( lastslash != NULL ) + { + savefilenameinzip = lastslash+1; // base filename follows last slash. + } + } + + /**/ + err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi, + NULL,0,NULL,0,NULL /* comment*/, + (opt_compress_level != 0) ? Z_DEFLATED : 0, + opt_compress_level,0, + /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */ + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + password,crcFile, zip64); + + if (err != ZIP_OK) + printf("error in opening %s in zipfile\n",filenameinzip); + else + { + fin = FOPEN_FUNC(filenameinzip,"rb"); + if (fin==NULL) + { + err=ZIP_ERRNO; + printf("error in opening %s for reading\n",filenameinzip); + } + } + + if (err == ZIP_OK) + do + { + err = ZIP_OK; + size_read = (int)fread(buf,1,size_buf,fin); + if (size_read < size_buf) + if (feof(fin)==0) + { + printf("error in reading %s\n",filenameinzip); + err = ZIP_ERRNO; + } + + if (size_read>0) + { + err = zipWriteInFileInZip (zf,buf,size_read); + if (err<0) + { + printf("error in writing %s in the zipfile\n", + filenameinzip); + } + + } + } while ((err == ZIP_OK) && (size_read>0)); + + if (fin) + fclose(fin); + + if (err<0) + err=ZIP_ERRNO; + else + { + err = zipCloseFileInZip(zf); + if (err!=ZIP_OK) + printf("error in closing %s in the zipfile\n", + filenameinzip); + } + } + } + errclose = zipClose(zf,NULL); + if (errclose != ZIP_OK) + printf("error in closing %s\n",filename_try); + } + else + { + do_help(); + } + + free(buf); + return 0; +} diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/minizip.pc.in b/test/zlib/zlib-1.2.8/contrib/minizip/minizip.pc.in new file mode 100644 index 000000000..69b5b7fdc --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/minizip.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@/minizip + +Name: minizip +Description: Minizip zip file manipulation library +Requires: +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -lminizip +Libs.private: -lz +Cflags: -I${includedir} diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/mztools.c b/test/zlib/zlib-1.2.8/contrib/minizip/mztools.c new file mode 100644 index 000000000..96891c2e0 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/mztools.c @@ -0,0 +1,291 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +/* Code */ +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#define READ_8(adr) ((unsigned char)*(adr)) +#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) +#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) + +#define WRITE_8(buff, n) do { \ + *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ +} while(0) +#define WRITE_16(buff, n) do { \ + WRITE_8((unsigned char*)(buff), n); \ + WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ +} while(0) +#define WRITE_32(buff, n) do { \ + WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ + WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ +} while(0) + +extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) +const char* file; +const char* fileOut; +const char* fileOutTmp; +uLong* nRecovered; +uLong* bytesRecovered; +{ + int err = Z_OK; + FILE* fpZip = fopen(file, "rb"); + FILE* fpOut = fopen(fileOut, "wb"); + FILE* fpOutCD = fopen(fileOutTmp, "wb"); + if (fpZip != NULL && fpOut != NULL) { + int entries = 0; + uLong totalBytes = 0; + char header[30]; + char filename[1024]; + char extra[1024]; + int offset = 0; + int offsetCD = 0; + while ( fread(header, 1, 30, fpZip) == 30 ) { + int currentOffset = offset; + + /* File entry */ + if (READ_32(header) == 0x04034b50) { + unsigned int version = READ_16(header + 4); + unsigned int gpflag = READ_16(header + 6); + unsigned int method = READ_16(header + 8); + unsigned int filetime = READ_16(header + 10); + unsigned int filedate = READ_16(header + 12); + unsigned int crc = READ_32(header + 14); /* crc */ + unsigned int cpsize = READ_32(header + 18); /* compressed size */ + unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ + unsigned int fnsize = READ_16(header + 26); /* file name length */ + unsigned int extsize = READ_16(header + 28); /* extra field length */ + filename[0] = extra[0] = '\0'; + + /* Header */ + if (fwrite(header, 1, 30, fpOut) == 30) { + offset += 30; + } else { + err = Z_ERRNO; + break; + } + + /* Filename */ + if (fnsize > 0) { + if (fnsize < sizeof(filename)) { + if (fread(filename, 1, fnsize, fpZip) == fnsize) { + if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { + offset += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (extsize < sizeof(extra)) { + if (fread(extra, 1, extsize, fpZip) == extsize) { + if (fwrite(extra, 1, extsize, fpOut) == extsize) { + offset += extsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } + + /* Data */ + { + int dataSize = cpsize; + if (dataSize == 0) { + dataSize = uncpsize; + } + if (dataSize > 0) { + char* data = malloc(dataSize); + if (data != NULL) { + if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { + if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { + offset += dataSize; + totalBytes += dataSize; + } else { + err = Z_ERRNO; + } + } else { + err = Z_ERRNO; + } + free(data); + if (err != Z_OK) { + break; + } + } else { + err = Z_MEM_ERROR; + break; + } + } + } + + /* Central directory entry */ + { + char header[46]; + char* comment = ""; + int comsize = (int) strlen(comment); + WRITE_32(header, 0x02014b50); + WRITE_16(header + 4, version); + WRITE_16(header + 6, version); + WRITE_16(header + 8, gpflag); + WRITE_16(header + 10, method); + WRITE_16(header + 12, filetime); + WRITE_16(header + 14, filedate); + WRITE_32(header + 16, crc); + WRITE_32(header + 20, cpsize); + WRITE_32(header + 24, uncpsize); + WRITE_16(header + 28, fnsize); + WRITE_16(header + 30, extsize); + WRITE_16(header + 32, comsize); + WRITE_16(header + 34, 0); /* disk # */ + WRITE_16(header + 36, 0); /* int attrb */ + WRITE_32(header + 38, 0); /* ext attrb */ + WRITE_32(header + 42, currentOffset); + /* Header */ + if (fwrite(header, 1, 46, fpOutCD) == 46) { + offsetCD += 46; + + /* Filename */ + if (fnsize > 0) { + if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { + offsetCD += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { + offsetCD += extsize; + } else { + err = Z_ERRNO; + break; + } + } + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { + offsetCD += comsize; + } else { + err = Z_ERRNO; + break; + } + } + + + } else { + err = Z_ERRNO; + break; + } + } + + /* Success */ + entries++; + + } else { + break; + } + } + + /* Final central directory */ + { + int entriesZip = entries; + char header[22]; + char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; + int comsize = (int) strlen(comment); + if (entriesZip > 0xffff) { + entriesZip = 0xffff; + } + WRITE_32(header, 0x06054b50); + WRITE_16(header + 4, 0); /* disk # */ + WRITE_16(header + 6, 0); /* disk # */ + WRITE_16(header + 8, entriesZip); /* hack */ + WRITE_16(header + 10, entriesZip); /* hack */ + WRITE_32(header + 12, offsetCD); /* size of CD */ + WRITE_32(header + 16, offset); /* offset to CD */ + WRITE_16(header + 20, comsize); /* comment */ + + /* Header */ + if (fwrite(header, 1, 22, fpOutCD) == 22) { + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { + err = Z_ERRNO; + } + } + + } else { + err = Z_ERRNO; + } + } + + /* Final merge (file + central directory) */ + fclose(fpOutCD); + if (err == Z_OK) { + fpOutCD = fopen(fileOutTmp, "rb"); + if (fpOutCD != NULL) { + int nRead; + char buffer[8192]; + while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { + if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { + err = Z_ERRNO; + break; + } + } + fclose(fpOutCD); + } + } + + /* Close */ + fclose(fpZip); + fclose(fpOut); + + /* Wipe temporary file */ + (void)remove(fileOutTmp); + + /* Number of recovered entries */ + if (err == Z_OK) { + if (nRecovered != NULL) { + *nRecovered = entries; + } + if (bytesRecovered != NULL) { + *bytesRecovered = totalBytes; + } + } + } else { + err = Z_STREAM_ERROR; + } + return err; +} diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/mztools.h b/test/zlib/zlib-1.2.8/contrib/minizip/mztools.h new file mode 100644 index 000000000..a49a426ec --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/mztools.h @@ -0,0 +1,37 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +#ifndef _zip_tools_H +#define _zip_tools_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#include "unzip.h" + +/* Repair a ZIP file (missing central directory) + file: file to recover + fileOut: output file after recovery + fileOutTmp: temporary file name used for recovery +*/ +extern int ZEXPORT unzRepair(const char* file, + const char* fileOut, + const char* fileOutTmp, + uLong* nRecovered, + uLong* bytesRecovered); + + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/unzip.c b/test/zlib/zlib-1.2.8/contrib/minizip/unzip.c new file mode 100644 index 000000000..909350435 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/unzip.c @@ -0,0 +1,2125 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + + ------------------------------------------------------------------------------------ + Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of + compatibility with older software. The following is from the original crypt.c. + Code woven in by Terry Thorsen 1/2003. + + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + ------------------------------------------------------------------------------------ + + Changes in unzip.c + + 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos + 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* + 2007-2008 - Even Rouault - Remove old C style function prototypes + 2007-2008 - Even Rouault - Add unzip support for ZIP64 + + Copyright (C) 2007-2008 Even Rouault + + + Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). + Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G + should only read the compressed/uncompressed size from the Zip64 format if + the size from normal header was 0xFFFFFFFF + Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant + Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) + Patch created by Daniel Borca + + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + + Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson + +*/ + + +#include +#include +#include + +#ifndef NOUNCRYPT + #define NOUNCRYPT +#endif + +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info64_internal_s +{ + ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ +} unz_file_info64_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ + ZPOS64_T total_out_64; + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ + ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip64_read_info_s; + + +/* unz64_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + int is64bitOpenFunction; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info64 gi; /* public global information */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T num_file; /* number of the current file in the zipfile*/ + ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ + ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ + ZPOS64_T central_pos; /* position of the beginning of the central dir*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info64 cur_file_info; /* public info about the current file in zip*/ + unz_file_info64_internal cur_file_info_internal; /* private info about it*/ + file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; + + int isZip64; + +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const z_crc_t* pcrc_32_tab; +# endif +} unz64_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unz64local_getByte OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unz64local_getShort OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX)); + + +local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX) +{ + ZPOS64_T x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<24; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<32; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<40; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<48; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<56; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, + const char* fileName2, + int iCaseSensitivity) + +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + + +/* + Locate the Central directory 64 of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream)); + +local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) + return 0; + + /* total number of disks */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + if (uL != 0x06064b50) + return 0; + + return relativeOffset; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +local unzFile unzOpenInternal (const void *path, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def, + int is64bitOpenFunction) +{ + unz64_s us; + unz64_s *s; + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + us.z_filefunc.zseek32_file = NULL; + us.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); + else + us.z_filefunc = *pzlib_filefunc64_32_def; + us.is64bitOpenFunction = is64bitOpenFunction; + + + + us.filestream = ZOPEN64(us.z_filefunc, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); + if (central_pos) + { + uLong uS; + ZPOS64_T uL64; + + us.isZip64 = 1; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* size of zip64 end of central directory record */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version made by */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version needed to extract */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + us.gi.size_comment = 0; + } + else + { + central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + us.isZip64 = 0; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.gi.number_entry = uL; + + /* total number of entries in the central dir */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + number_entry_CD = uL; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.size_central_dir = uL; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.offset_central_dir = uL; + + /* zipfile comment length */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + } + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE64(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + /* to do : check if number_entry is not truncated */ + pglobal_info32->number_entry = (uLong)s->gi.number_entry; + pglobal_info32->size_comment = s->gi.size_comment; + return UNZ_OK; +} +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) +{ + ZPOS64_T uDate; + uDate = (ZPOS64_T)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unz64local_GetCurrentFileInfoInternal (unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz64_s* s; + unz_file_info64 file_info; + unz_file_info64_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + uLong uL; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.compressed_size = uL; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.uncompressed_size = uL; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + // relative offset of local header + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info_internal.offset_curfile = uL; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + // Read extrafield + if ((err==UNZ_OK) && (extraField!=NULL)) + { + ZPOS64_T uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + + lSeek += file_info.size_file_extra - (uLong)uSizeRead; + } + else + lSeek += file_info.size_file_extra; + + + if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) + { + uLong acc = 0; + + // since lSeek now points to after the extra field we need to move back + lSeek -= file_info.size_file_extra; + + if (lSeek!=0) + { + if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + while(acc < file_info.size_file_extra) + { + uLong headerId; + uLong dataSize; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) + err=UNZ_ERRNO; + + /* ZIP64 extra fields */ + if (headerId == 0x0001) + { + uLong uL; + + if(file_info.uncompressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.compressed_size == MAXU32) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info_internal.offset_curfile == MAXU32) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.disk_num_start == MAXU32) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + } + + } + else + { + if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) + err=UNZ_ERRNO; + } + + acc += 2 + 2 + dataSize; + } + } + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, + unz_file_info64 * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, + unz_file_info * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + int err; + unz_file_info64 file_info64; + err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); + if ((err==UNZ_OK) && (pfile_info != NULL)) + { + pfile_info->version = file_info64.version; + pfile_info->version_needed = file_info64.version_needed; + pfile_info->flag = file_info64.flag; + pfile_info->compression_method = file_info64.compression_method; + pfile_info->dosDate = file_info64.dosDate; + pfile_info->crc = file_info64.crc; + + pfile_info->size_filename = file_info64.size_filename; + pfile_info->size_file_extra = file_info64.size_file_extra; + pfile_info->size_file_comment = file_info64.size_file_comment; + + pfile_info->disk_num_start = file_info64.disk_num_start; + pfile_info->internal_fa = file_info64.internal_fa; + pfile_info->external_fa = file_info64.external_fa; + + pfile_info->tmu_date = file_info64.tmu_date, + + + pfile_info->compressed_size = (uLong)file_info64.compressed_size; + pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; + + } + return err; +} +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (unzFile file) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz64_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info64 cur_file_infoSaved; + unz_file_info64_internal cur_file_info_internalSaved; + ZPOS64_T num_fileSaved; + ZPOS64_T pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo64(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; // offset in file + ZPOS64_T num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) +{ + unz64_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + int err = unzGetFilePos64(file,&file_pos64); + if (err==UNZ_OK) + { + file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; + file_pos->num_of_file = (uLong)file_pos64.num_of_file; + } + return err; +} + +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) +{ + unz64_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + if (file_pos == NULL) + return UNZ_PARAMERROR; + + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + return unzGoToFilePos64(file,&file_pos64); +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, + ZPOS64_T * poffset_local_extrafield, + uInt * psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, + int* level, int raw, const char* password) +{ + int err=UNZ_OK; + uInt iSizeVar; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->total_out_64=0; + pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw=1; +#endif + } + else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = 0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + s->encrypted = 0; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + s=(unz64_s*)file; + if (file==NULL) + return 0; //UNZ_PARAMERROR; + pfile_in_zip_read_info=s->pfile_in_zip_read; + if (pfile_in_zip_read_info==NULL) + return 0; //UNZ_PARAMERROR; + return pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile; +} + +/** Addition for GDAL : END */ + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->read_buffer == NULL) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + + pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; + bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; + + err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); + pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err==BZ_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=BZ_OK) + break; +#endif + } // end Z_BZIP2ED + else + { + ZPOS64_T uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + ZPOS64_T uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + +extern ZPOS64_T ZEXPORT unztell64 (unzFile file) +{ + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return (ZPOS64_T)-1; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return (ZPOS64_T)-1; + + return pfile_in_zip_read_info->total_out_64; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* +Read extra field from the current file (opened by unzOpenCurrentFile) +This is the local-header version of the extra field (sometimes, there is +more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + uInt read_now; + ZPOS64_T size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) +{ + unz64_s* s; + uLong uReadThis ; + if (file==NULL) + return (int)UNZ_PARAMERROR; + s=(unz64_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) +{ + unz64_s* s; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file==s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern uLong ZEXPORT unzGetOffset (unzFile file) +{ + ZPOS64_T offset64; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + offset64 = unzGetOffset64(file); + return (uLong)offset64; +} + +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) +{ + return unzSetOffset64(file,pos); +} diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/unzip.h b/test/zlib/zlib-1.2.8/contrib/minizip/unzip.h new file mode 100644 index 000000000..2104e3915 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/unzip.h @@ -0,0 +1,437 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------------- + + Changes + + See header of unzip64.c + +*/ + +#ifndef _unz64_H +#define _unz64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +extern unzFile ZEXPORT unzOpen64 OF((const void *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality +*/ + + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, + zlib_filefunc64_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unz64Open, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzCloseCurrentFile before call unzClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); + +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +/** Addition for GDAL : END */ + + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); + +extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz64_H */ diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/zip.c b/test/zlib/zlib-1.2.8/contrib/minizip/zip.c new file mode 100644 index 000000000..ea54853e8 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/zip.c @@ -0,0 +1,2007 @@ +/* zip.c -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + Oct-2009 - Mathias Svensson - Remove old C style function prototypes + Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives + Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. + Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data + It is used when recreting zip archive with RAW when deleting items from a zip. + ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed. + Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + +*/ + + +#include +#include +#include +#include +#include "zlib.h" +#include "zip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform depedent */ +#endif + +#ifndef Z_BUFSIZE +#define Z_BUFSIZE (64*1024) //(16384) +#endif + +#ifndef Z_MAXFILENAMEINZIP +#define Z_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +/* +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) +*/ + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + + +// NOT sure that this work on ALL platform +#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef DEF_MEM_LEVEL +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#endif +const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) +#define ZIP64ENDHEADERMAGIC (0x6064b50) +#define ZIP64ENDLOCHEADERMAGIC (0x7064b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignement */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + ZPOS64_T pos_local_header; /* offset of the local header of the file + currenty writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralExtra; + uLong size_centralheader; /* size of the central header for cur file */ + uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method of file currenty wr.*/ + int raw; /* 1 for directly writing raw data */ + Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; + int encrypt; + int zip64; /* Add ZIP64 extened information in the extra field */ + ZPOS64_T pos_zip64extrainfo; + ZPOS64_T totalCompressedData; + ZPOS64_T totalUncompressedData; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const z_crc_t* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile64_info; + +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + linkedlist_data central_dir;/* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + curfile64_info ci; /* info on the file curretly writing */ + + ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ + ZPOS64_T add_position_when_writting_offset; + ZPOS64_T number_entry; + +#ifndef NO_ADDFILEINEXISTINGZIP + char *globalcomment; +#endif + +} zip64_internal; + + +#ifndef NOCRYPT +#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +#include "crypt.h" +#endif + +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + ldi = (linkedlist_datablock_internal*) + ALLOC(sizeof(linkedlist_datablock_internal)); + if (ldi!=NULL) + { + ldi->next_datablock = NULL ; + ldi->filled_in_this_block = 0 ; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; + } + return ldi; +} + +local void free_datablock(linkedlist_datablock_internal* ldi) +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(linkedlist_data* ll) +{ + ll->first_block = ll->last_block = NULL; +} + +local void free_linkedlist(linkedlist_data* ll) +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + + +local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll==NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len>0) + { + uInt copy_this; + uInt i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block==0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock ; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + + + +/****************************************************************************/ + +#ifndef NO_ADDFILEINEXISTINGZIP +/* =========================================================================== + Inputs a long in LSB order to the given file + nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) +*/ + +local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); +local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) +{ + unsigned char buf[8]; + int n; + for (n = 0; n < nbByte; n++) + { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (x != 0) + { /* data overflow - hack for ZIP64 (X Roche) */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } + + if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); +local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) +{ + unsigned char* buf=(unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + + if (x != 0) + { /* data overflow - hack for ZIP64 */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } +} + +/****************************************************************************/ + + +local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) +{ + uLong year = (uLong)ptm->tm_year; + if (year>=1980) + year-=1980; + else if (year>=80) + year-=80; + return + (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | + ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + + +/****************************************************************************/ + +local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); + +local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return ZIP_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return ZIP_ERRNO; + else + return ZIP_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); + + +local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) +{ + ZPOS64_T x; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<24; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<32; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<40; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<48; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<56; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + + return err; +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* +Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before +the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + { + // Signature "0x07064b50" Zip64 end of central directory locater + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + } + + if (uPosFound!=0) + break; + } + + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) + return 0; + + /* total number of disks */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto Zip64 end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' + return 0; + + return relativeOffset; +} + +int LoadCentralDirectoryRecord(zip64_internal* pziinit) +{ + int err=ZIP_OK; + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory */ + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry; + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + uLong VersionMadeBy; + uLong VersionNeeded; + uLong size_comment; + + int hasZIP64Record = 0; + + // check first if we find a ZIP64 record + central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream); + if(central_pos > 0) + { + hasZIP64Record = 1; + } + else if(central_pos == 0) + { + central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream); + } + +/* disable to allow appending to empty ZIP archive + if (central_pos==0) + err=ZIP_ERRNO; +*/ + + if(hasZIP64Record) + { + ZPOS64_T sizeEndOfCentralDirectory; + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* size of zip64 end of central directory record */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version made by */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version needed to extract */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + // TODO.. + // read the comment from the standard central header. + size_comment = 0; + } + else + { + // Read End of central Directory info + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir on this disk */ + number_entry = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry = uL; + + /* total number of entries in the central dir */ + number_entry_CD = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry_CD = uL; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + size_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + size_central_dir = uL; + + /* offset of start of central directory with respect to the starting disk number */ + offset_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + offset_central_dir = uL; + + + /* zipfile global comment length */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK) + err=ZIP_ERRNO; + } + + if ((central_posz_filefunc, pziinit->filestream); + return ZIP_ERRNO; + } + + if (size_comment>0) + { + pziinit->globalcomment = (char*)ALLOC(size_comment+1); + if (pziinit->globalcomment) + { + size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment); + pziinit->globalcomment[size_comment]=0; + } + } + + byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); + pziinit->add_position_when_writting_offset = byte_before_the_zipfile; + + { + ZPOS64_T size_central_dir_to_read = size_central_dir; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read = (void*)ALLOC(buf_size); + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + while ((size_central_dir_to_read>0) && (err==ZIP_OK)) + { + ZPOS64_T read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + + if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this) + err=ZIP_ERRNO; + + if (err==ZIP_OK) + err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); + + size_central_dir_to_read-=read_this; + } + TRYFREE(buf_read); + } + pziinit->begin_pos = byte_before_the_zipfile; + pziinit->number_entry = number_entry_CD; + + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + return err; +} + + +#endif /* !NO_ADDFILEINEXISTINGZIP*/ + + +/************************************************************/ +extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) +{ + zip64_internal ziinit; + zip64_internal* zi; + int err=ZIP_OK; + + ziinit.z_filefunc.zseek32_file = NULL; + ziinit.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); + else + ziinit.z_filefunc = *pzlib_filefunc64_32_def; + + ziinit.filestream = ZOPEN64(ziinit.z_filefunc, + pathname, + (append == APPEND_STATUS_CREATE) ? + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); + + if (ziinit.filestream == NULL) + return NULL; + + if (append == APPEND_STATUS_CREATEAFTER) + ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); + + ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + ziinit.add_position_when_writting_offset = 0; + init_linkedlist(&(ziinit.central_dir)); + + + + zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); + if (zi==NULL) + { + ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); + return NULL; + } + + /* now we add file in a zipfile */ +# ifndef NO_ADDFILEINEXISTINGZIP + ziinit.globalcomment = NULL; + if (append == APPEND_STATUS_ADDINZIP) + { + // Read and Cache Central Directory Records + err = LoadCentralDirectoryRecord(&ziinit); + } + + if (globalcomment) + { + *globalcomment = ziinit.globalcomment; + } +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + + if (err != ZIP_OK) + { +# ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(ziinit.globalcomment); +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + TRYFREE(zi); + return NULL; + } + else + { + *zi = ziinit; + return (zipFile)zi; + } +} + +extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + + + +extern zipFile ZEXPORT zipOpen (const char* pathname, int append) +{ + return zipOpen3((const void*)pathname,append,NULL,NULL); +} + +extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append) +{ + return zipOpen3(pathname,append,NULL,NULL); +} + +int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) +{ + /* write the local header */ + int err; + uInt size_filename = (uInt)strlen(filename); + uInt size_extrafield = size_extrafield_local; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); + + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); + + // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ + } + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); + + if(zi->ci.zip64) + { + size_extrafield += 20; + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2); + + if ((err==ZIP_OK) && (size_filename > 0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) + err = ZIP_ERRNO; + } + + if ((err==ZIP_OK) && (size_extrafield_local > 0)) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) + err = ZIP_ERRNO; + } + + + if ((err==ZIP_OK) && (zi->ci.zip64)) + { + // write the Zip64 extended info + short HeaderID = 1; + short DataSize = 16; + ZPOS64_T CompressedSize = 0; + ZPOS64_T UncompressedSize = 0; + + // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) + zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); + } + + return err; +} + +/* + NOTE. + When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped + before calling this function it can be done with zipRemoveExtraInfoBlock + + It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize + unnecessary allocations. + */ +extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase, int zip64) +{ + zip64_internal* zi; + uInt size_filename; + uInt size_comment; + uInt i; + int err = ZIP_OK; + +# ifdef NOCRYPT + (crcForCrypting); + if (password != NULL) + return ZIP_PARAMERROR; +# endif + + if (file == NULL) + return ZIP_PARAMERROR; + +#ifdef HAVE_BZIP2 + if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) + return ZIP_PARAMERROR; +#else + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; +#endif + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + if (filename==NULL) + filename="-"; + + if (comment==NULL) + size_comment = 0; + else + size_comment = (uInt)strlen(comment); + + size_filename = (uInt)strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else + zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); + } + + zi->ci.flag = flagBase; + if ((level==8) || (level==9)) + zi->ci.flag |= 2; + if (level==2) + zi->ci.flag |= 4; + if (level==1) + zi->ci.flag |= 6; + if (password != NULL) + zi->ci.flag |= 1; + + zi->ci.crc32 = 0; + zi->ci.method = method; + zi->ci.encrypt = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream); + + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; + zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data + + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree); + + zi->ci.size_centralExtra = size_extrafield_global; + zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); + zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + if(zi->ci.pos_local_header >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4); + + for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ + size_extrafield_global+i) = *(comment+i); + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + zi->ci.zip64 = zip64; + zi->ci.totalCompressedData = 0; + zi->ci.totalUncompressedData = 0; + zi->ci.pos_zip64extrainfo = 0; + + err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local); + +#ifdef HAVE_BZIP2 + zi->ci.bstream.avail_in = (uInt)0; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + zi->ci.bstream.total_in_hi32 = 0; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_out_hi32 = 0; + zi->ci.bstream.total_out_lo32 = 0; +#endif + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + zi->ci.stream.data_type = Z_BINARY; + +#ifdef HAVE_BZIP2 + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) +#else + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) +#endif + { + if(zi->ci.method == Z_DEFLATED) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)0; + + if (windowBits>0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); + + if (err==Z_OK) + zi->ci.stream_initialised = Z_DEFLATED; + } + else if(zi->ci.method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + // Init BZip stuff here + zi->ci.bstream.bzalloc = 0; + zi->ci.bstream.bzfree = 0; + zi->ci.bstream.opaque = (voidpf)0; + + err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35); + if(err == BZ_OK) + zi->ci.stream_initialised = Z_BZIP2ED; +#endif + } + + } + +# ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err==Z_OK) && (password != NULL)) + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + zi->ci.encrypt = 1; + zi->ci.pcrc_32_tab = get_crc_table(); + /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ + + sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) + err = ZIP_ERRNO; + } +# endif + + if (err==Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, versionMadeBy, flagBase, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +local int zip64FlushWriteBuffer(zip64_internal* zi) +{ + int err=ZIP_OK; + + if (zi->ci.encrypt != 0) + { +#ifndef NOCRYPT + uInt i; + int t; + for (i=0;ici.pos_in_buffered_data;i++) + zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); +#endif + } + + if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data) + err = ZIP_ERRNO; + + zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data; + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED) + { + zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_in_hi32 = 0; + } + else +#endif + { + zi->ci.totalUncompressedData += zi->ci.stream.total_in; + zi->ci.stream.total_in = 0; + } + + + zi->ci.pos_in_buffered_data = 0; + + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) +{ + zip64_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw)) + { + zi->ci.bstream.next_in = (void*)buf; + zi->ci.bstream.avail_in = len; + err = BZ_RUN_OK; + + while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0)) + { + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + + + if(err != BZ_RUN_OK) + break; + + if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; +// uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ; + } + } + + if(err == BZ_RUN_OK) + err = ZIP_OK; + } + else +#endif + { + zi->ci.stream.next_in = (Bytef*)buf; + zi->ci.stream.avail_in = len; + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + + if(err != ZIP_OK) + break; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_NO_FLUSH); + if(uTotalOutBefore > zi->ci.stream.total_out) + { + int bBreak = 0; + bBreak++; + } + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + else + { + uInt copy_this,i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + + for (i = 0; i < copy_this; i++) + *(((char*)zi->ci.stream.next_out)+i) = + *(((const char*)zi->ci.stream.next_in)+i); + { + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out-= copy_this; + zi->ci.stream.next_in+= copy_this; + zi->ci.stream.next_out+= copy_this; + zi->ci.stream.total_in+= copy_this; + zi->ci.stream.total_out+= copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + }// while(...) + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) +{ + return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); +} + +extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) +{ + zip64_internal* zi; + ZPOS64_T compressed_size; + uLong invalidValue = 0xffffffff; + short datasize = 0; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + while (err==ZIP_OK) + { + uLong uTotalOutBefore; + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + } + else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { +#ifdef HAVE_BZIP2 + err = BZ_FINISH_OK; + while (err==BZ_FINISH_OK) + { + uLong uTotalOutBefore; + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.bstream.total_out_lo32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); + if(err == BZ_STREAM_END) + err = Z_STREAM_END; + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore); + } + + if(err == BZ_FINISH_OK) + err = ZIP_OK; +#endif + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + { + if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO) + err = ZIP_ERRNO; + } + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + int tmp_err = deflateEnd(&zi->ci.stream); + if (err == ZIP_OK) + err = tmp_err; + zi->ci.stream_initialised = 0; + } +#ifdef HAVE_BZIP2 + else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); + if (err==ZIP_OK) + err = tmperr; + zi->ci.stream_initialised = 0; + } +#endif + + if (!zi->ci.raw) + { + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = zi->ci.totalUncompressedData; + } + compressed_size = zi->ci.totalCompressedData; + +# ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +# endif + + // update Current Item crc and sizes, + if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) + { + /*version Made by*/ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2); + /*version needed*/ + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2); + + } + + zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ + + + if(compressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ + + /// set internal file attributes field + if (zi->ci.stream.data_type == Z_ASCII) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); + + if(uncompressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ + + // Add ZIP64 extra info field for uncompressed size + if(uncompressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for compressed size + if(compressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for relative offset to local file header of current file + if(zi->ci.pos_local_header >= 0xffffffff) + datasize += 8; + + if(datasize > 0) + { + char* p = NULL; + + if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) + { + // we can not write more data to the buffer that we have room for. + return ZIP_BADZIPFILE; + } + + p = zi->ci.central_header + zi->ci.size_centralheader; + + // Add Extra Information Header for 'ZIP64 information' + zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID + p += 2; + zip64local_putValue_inmemory(p, datasize, 2); // DataSize + p += 2; + + if(uncompressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, uncompressed_size, 8); + p += 8; + } + + if(compressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, compressed_size, 8); + p += 8; + } + + if(zi->ci.pos_local_header >= 0xffffffff) + { + zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); + p += 8; + } + + // Update how much extra free space we got in the memory buffer + // and increase the centralheader size so the new ZIP64 fields are included + // ( 4 below is the size of HeaderID and DataSize field ) + zi->ci.size_centralExtraFree -= datasize + 4; + zi->ci.size_centralheader += datasize + 4; + + // Update the extra info size field + zi->ci.size_centralExtra += datasize + 4; + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2); + } + + if (err==ZIP_OK) + err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); + + free(zi->ci.central_header); + + if (err==ZIP_OK) + { + // Update the LocalFileHeader with the new values. + + ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if(uncompressed_size >= 0xffffffff || compressed_size >= 0xffffffff ) + { + if(zi->ci.pos_zip64extrainfo > 0) + { + // Update the size in the ZIP64 extended field. + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); + } + else + err = ZIP_BADZIPFILE; // Caller passed zip64 = 0, so no room for zip64 info -> fatal + } + else + { + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + } + + if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + } + + zi->number_entry ++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip (zipFile file) +{ + return zipCloseFileInZipRaw (file,0,0); +} + +int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) +{ + int err = ZIP_OK; + ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); + + /*num disks*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + /*relative offset*/ + if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); + + /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); + + return err; +} + +int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + uLong Zip64DataSize = 44; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ? + + if (err==ZIP_OK) /* version made by */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* version needed */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); + } + return err; +} +int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + /*signature*/ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + { + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + } + + if (err==ZIP_OK) /* total number of entries in the central dir */ + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff) + { + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); + } + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); + } + + return err; +} + +int Write_GlobalComment(zip64_internal* zi, const char* global_comment) +{ + int err = ZIP_OK; + uInt size_global_comment = 0; + + if(global_comment != NULL) + size_global_comment = (uInt)strlen(global_comment); + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); + + if (err == ZIP_OK && size_global_comment > 0) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + } + return err; +} + +extern int ZEXPORT zipClose (zipFile file, const char* global_comment) +{ + zip64_internal* zi; + int err = 0; + uLong size_centraldir = 0; + ZPOS64_T centraldir_pos_inzip; + ZPOS64_T pos; + + if (file == NULL) + return ZIP_PARAMERROR; + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + } + +#ifndef NO_ADDFILEINEXISTINGZIP + if (global_comment==NULL) + global_comment = zi->globalcomment; +#endif + + centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (err==ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block; + while (ldi!=NULL) + { + if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block) + err = ZIP_ERRNO; + } + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + free_linkedlist(&(zi->central_dir)); + + pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff || zi->number_entry > 0xFFFF) + { + ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); + Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); + } + + if (err==ZIP_OK) + err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + if(err == ZIP_OK) + err = Write_GlobalComment(zi, global_comment); + + if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} + +extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) +{ + char* p = pData; + int size = 0; + char* pNewHeader; + char* pTmp; + short header; + short dataSize; + + int retVal = ZIP_OK; + + if(pData == NULL || *dataLen < 4) + return ZIP_PARAMERROR; + + pNewHeader = (char*)ALLOC(*dataLen); + pTmp = pNewHeader; + + while(p < (pData + *dataLen)) + { + header = *(short*)p; + dataSize = *(((short*)p)+1); + + if( header == sHeader ) // Header found. + { + p += dataSize + 4; // skip it. do not copy to temp buffer + } + else + { + // Extra Info block should not be removed, So copy it to the temp buffer. + memcpy(pTmp, p, dataSize + 4); + p += dataSize + 4; + size += dataSize + 4; + } + + } + + if(size < *dataLen) + { + // clean old extra info block. + memset(pData,0, *dataLen); + + // copy the new extra info block over the old + if(size > 0) + memcpy(pData, pNewHeader, size); + + // set the new extra info size + *dataLen = size; + + retVal = ZIP_OK; + } + else + retVal = ZIP_ERRNO; + + TRYFREE(pNewHeader); + + return retVal; +} diff --git a/test/zlib/zlib-1.2.8/contrib/minizip/zip.h b/test/zlib/zlib-1.2.8/contrib/minizip/zip.h new file mode 100644 index 000000000..8aaebb623 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/minizip/zip.h @@ -0,0 +1,362 @@ +/* zip.h -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------- + + Changes + + See header of zip.h + +*/ + +#ifndef _zip12_H +#define _zip12_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#define HAVE_BZIP2 + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ +/* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); +extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); +/* + Create a zipfile. + pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on + an Unix computer "zlib/zlib113.zip". + if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. + (useful if the file contain a self extractor code) + if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will + add files in existing zip (be sure you don't add file that doesn't exist) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. +*/ + +/* Note : there is no delete function into a zipfile. + If you want delete file into a zipfile, you must open a zipfile, and create another + Of couse, you can use RAW reading and writing to copy the file you did not want delte +*/ + +extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc64_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); + +extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int zip64)); + +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) + zip64 is set to 1 if a zip64 extended information block should be added to the local file header. + this MUST be '1' if the uncompressed size is >= 0xffffffff. + +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + + +extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int zip64)); +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting)); + +extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + int zip64 + )); + +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCrypting : crc of file to compress (needed for crypting) + */ + +extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase + )); + + +extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase, + int zip64 + )); +/* + Same than zipOpenNewFileInZip4, except + versionMadeBy : value for Version made by field + flag : value for flag field (compression level info will be added) + */ + + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); + +extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, + ZPOS64_T uncompressed_size, + uLong crc32)); + +/* + Close the current file in the zipfile, for file opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + + +extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); +/* + zipRemoveExtraInfoBlock - Added by Mathias Svensson + + Remove extra information block from a extra information data for the local file header or central directory header + + It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. + + 0x0001 is the signature header for the ZIP64 extra information blocks + + usage. + Remove ZIP64 Extra information from a central director extra field data + zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); + + Remove ZIP64 Extra information from a Local File Header extra field data + zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip64_H */ diff --git a/test/zlib/zlib-1.2.8/contrib/pascal/example.pas b/test/zlib/zlib-1.2.8/contrib/pascal/example.pas new file mode 100644 index 000000000..5518b36a7 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/pascal/example.pas @@ -0,0 +1,599 @@ +(* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-2003 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Pascal translation + * Copyright (C) 1998 by Jacques Nomssi Nzali. + * For conditions of distribution and use, see copyright notice in readme.txt + * + * Adaptation to the zlibpas interface + * Copyright (C) 2003 by Cosmin Truta. + * For conditions of distribution and use, see copyright notice in readme.txt + *) + +program example; + +{$DEFINE TEST_COMPRESS} +{DO NOT $DEFINE TEST_GZIO} +{$DEFINE TEST_DEFLATE} +{$DEFINE TEST_INFLATE} +{$DEFINE TEST_FLUSH} +{$DEFINE TEST_SYNC} +{$DEFINE TEST_DICT} + +uses SysUtils, zlibpas; + +const TESTFILE = 'foo.gz'; + +(* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + *) +const hello: PChar = 'hello, hello!'; + +const dictionary: PChar = 'hello'; + +var dictId: LongInt; (* Adler32 value of the dictionary *) + +procedure CHECK_ERR(err: Integer; msg: String); +begin + if err <> Z_OK then + begin + WriteLn(msg, ' error: ', err); + Halt(1); + end; +end; + +procedure EXIT_ERR(const msg: String); +begin + WriteLn('Error: ', msg); + Halt(1); +end; + +(* =========================================================================== + * Test compress and uncompress + *) +{$IFDEF TEST_COMPRESS} +procedure test_compress(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var err: Integer; + len: LongInt; +begin + len := StrLen(hello)+1; + + err := compress(compr, comprLen, hello, len); + CHECK_ERR(err, 'compress'); + + StrCopy(PChar(uncompr), 'garbage'); + + err := uncompress(uncompr, uncomprLen, compr, comprLen); + CHECK_ERR(err, 'uncompress'); + + if StrComp(PChar(uncompr), hello) <> 0 then + EXIT_ERR('bad uncompress') + else + WriteLn('uncompress(): ', PChar(uncompr)); +end; +{$ENDIF} + +(* =========================================================================== + * Test read/write of .gz files + *) +{$IFDEF TEST_GZIO} +procedure test_gzio(const fname: PChar; (* compressed file name *) + uncompr: Pointer; + uncomprLen: LongInt); +var err: Integer; + len: Integer; + zfile: gzFile; + pos: LongInt; +begin + len := StrLen(hello)+1; + + zfile := gzopen(fname, 'wb'); + if zfile = NIL then + begin + WriteLn('gzopen error'); + Halt(1); + end; + gzputc(zfile, 'h'); + if gzputs(zfile, 'ello') <> 4 then + begin + WriteLn('gzputs err: ', gzerror(zfile, err)); + Halt(1); + end; + {$IFDEF GZ_FORMAT_STRING} + if gzprintf(zfile, ', %s!', 'hello') <> 8 then + begin + WriteLn('gzprintf err: ', gzerror(zfile, err)); + Halt(1); + end; + {$ELSE} + if gzputs(zfile, ', hello!') <> 8 then + begin + WriteLn('gzputs err: ', gzerror(zfile, err)); + Halt(1); + end; + {$ENDIF} + gzseek(zfile, 1, SEEK_CUR); (* add one zero byte *) + gzclose(zfile); + + zfile := gzopen(fname, 'rb'); + if zfile = NIL then + begin + WriteLn('gzopen error'); + Halt(1); + end; + + StrCopy(PChar(uncompr), 'garbage'); + + if gzread(zfile, uncompr, uncomprLen) <> len then + begin + WriteLn('gzread err: ', gzerror(zfile, err)); + Halt(1); + end; + if StrComp(PChar(uncompr), hello) <> 0 then + begin + WriteLn('bad gzread: ', PChar(uncompr)); + Halt(1); + end + else + WriteLn('gzread(): ', PChar(uncompr)); + + pos := gzseek(zfile, -8, SEEK_CUR); + if (pos <> 6) or (gztell(zfile) <> pos) then + begin + WriteLn('gzseek error, pos=', pos, ', gztell=', gztell(zfile)); + Halt(1); + end; + + if gzgetc(zfile) <> ' ' then + begin + WriteLn('gzgetc error'); + Halt(1); + end; + + if gzungetc(' ', zfile) <> ' ' then + begin + WriteLn('gzungetc error'); + Halt(1); + end; + + gzgets(zfile, PChar(uncompr), uncomprLen); + uncomprLen := StrLen(PChar(uncompr)); + if uncomprLen <> 7 then (* " hello!" *) + begin + WriteLn('gzgets err after gzseek: ', gzerror(zfile, err)); + Halt(1); + end; + if StrComp(PChar(uncompr), hello + 6) <> 0 then + begin + WriteLn('bad gzgets after gzseek'); + Halt(1); + end + else + WriteLn('gzgets() after gzseek: ', PChar(uncompr)); + + gzclose(zfile); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with small buffers + *) +{$IFDEF TEST_DEFLATE} +procedure test_deflate(compr: Pointer; comprLen: LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; + len: LongInt; +begin + len := StrLen(hello)+1; + + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, 'deflateInit'); + + c_stream.next_in := hello; + c_stream.next_out := compr; + + while (c_stream.total_in <> len) and + (c_stream.total_out < comprLen) do + begin + c_stream.avail_out := 1; { force small buffers } + c_stream.avail_in := 1; + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + end; + + (* Finish the stream, still forcing small buffers: *) + while TRUE do + begin + c_stream.avail_out := 1; + err := deflate(c_stream, Z_FINISH); + if err = Z_STREAM_END then + break; + CHECK_ERR(err, 'deflate'); + end; + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); +end; +{$ENDIF} + +(* =========================================================================== + * Test inflate with small buffers + *) +{$IFDEF TEST_INFLATE} +procedure test_inflate(compr: Pointer; comprLen : LongInt; + uncompr: Pointer; uncomprLen : LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := 0; + d_stream.next_out := uncompr; + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + while (d_stream.total_out < uncomprLen) and + (d_stream.total_in < comprLen) do + begin + d_stream.avail_out := 1; (* force small buffers *) + d_stream.avail_in := 1; + err := inflate(d_stream, Z_NO_FLUSH); + if err = Z_STREAM_END then + break; + CHECK_ERR(err, 'inflate'); + end; + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + if StrComp(PChar(uncompr), hello) <> 0 then + EXIT_ERR('bad inflate') + else + WriteLn('inflate(): ', PChar(uncompr)); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with large buffers and dynamic change of compression level + *) +{$IFDEF TEST_DEFLATE} +procedure test_large_deflate(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; +begin + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_BEST_SPEED); + CHECK_ERR(err, 'deflateInit'); + + c_stream.next_out := compr; + c_stream.avail_out := Integer(comprLen); + + (* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + *) + c_stream.next_in := uncompr; + c_stream.avail_in := Integer(uncomprLen); + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + if c_stream.avail_in <> 0 then + EXIT_ERR('deflate not greedy'); + + (* Feed in already compressed data and switch to no compression: *) + deflateParams(c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in := compr; + c_stream.avail_in := Integer(comprLen div 2); + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + + (* Switch back to compressing mode: *) + deflateParams(c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in := uncompr; + c_stream.avail_in := Integer(uncomprLen); + err := deflate(c_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'deflate'); + + err := deflate(c_stream, Z_FINISH); + if err <> Z_STREAM_END then + EXIT_ERR('deflate should report Z_STREAM_END'); + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); +end; +{$ENDIF} + +(* =========================================================================== + * Test inflate with large buffers + *) +{$IFDEF TEST_INFLATE} +procedure test_large_inflate(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := Integer(comprLen); + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + while TRUE do + begin + d_stream.next_out := uncompr; (* discard the output *) + d_stream.avail_out := Integer(uncomprLen); + err := inflate(d_stream, Z_NO_FLUSH); + if err = Z_STREAM_END then + break; + CHECK_ERR(err, 'large inflate'); + end; + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + if d_stream.total_out <> 2 * uncomprLen + comprLen div 2 then + begin + WriteLn('bad large inflate: ', d_stream.total_out); + Halt(1); + end + else + WriteLn('large_inflate(): OK'); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with full flush + *) +{$IFDEF TEST_FLUSH} +procedure test_flush(compr: Pointer; var comprLen : LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; + len: Integer; +begin + len := StrLen(hello)+1; + + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, 'deflateInit'); + + c_stream.next_in := hello; + c_stream.next_out := compr; + c_stream.avail_in := 3; + c_stream.avail_out := Integer(comprLen); + err := deflate(c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, 'deflate'); + + Inc(PByteArray(compr)^[3]); (* force an error in first compressed block *) + c_stream.avail_in := len - 3; + + err := deflate(c_stream, Z_FINISH); + if err <> Z_STREAM_END then + CHECK_ERR(err, 'deflate'); + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); + + comprLen := c_stream.total_out; +end; +{$ENDIF} + +(* =========================================================================== + * Test inflateSync() + *) +{$IFDEF TEST_SYNC} +procedure test_sync(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen : LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := 2; (* just read the zlib header *) + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + d_stream.next_out := uncompr; + d_stream.avail_out := Integer(uncomprLen); + + inflate(d_stream, Z_NO_FLUSH); + CHECK_ERR(err, 'inflate'); + + d_stream.avail_in := Integer(comprLen-2); (* read all compressed data *) + err := inflateSync(d_stream); (* but skip the damaged part *) + CHECK_ERR(err, 'inflateSync'); + + err := inflate(d_stream, Z_FINISH); + if err <> Z_DATA_ERROR then + EXIT_ERR('inflate should report DATA_ERROR'); + (* Because of incorrect adler32 *) + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + WriteLn('after inflateSync(): hel', PChar(uncompr)); +end; +{$ENDIF} + +(* =========================================================================== + * Test deflate with preset dictionary + *) +{$IFDEF TEST_DICT} +procedure test_dict_deflate(compr: Pointer; comprLen: LongInt); +var c_stream: z_stream; (* compression stream *) + err: Integer; +begin + c_stream.zalloc := NIL; + c_stream.zfree := NIL; + c_stream.opaque := NIL; + + err := deflateInit(c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, 'deflateInit'); + + err := deflateSetDictionary(c_stream, dictionary, StrLen(dictionary)); + CHECK_ERR(err, 'deflateSetDictionary'); + + dictId := c_stream.adler; + c_stream.next_out := compr; + c_stream.avail_out := Integer(comprLen); + + c_stream.next_in := hello; + c_stream.avail_in := StrLen(hello)+1; + + err := deflate(c_stream, Z_FINISH); + if err <> Z_STREAM_END then + EXIT_ERR('deflate should report Z_STREAM_END'); + + err := deflateEnd(c_stream); + CHECK_ERR(err, 'deflateEnd'); +end; +{$ENDIF} + +(* =========================================================================== + * Test inflate with a preset dictionary + *) +{$IFDEF TEST_DICT} +procedure test_dict_inflate(compr: Pointer; comprLen: LongInt; + uncompr: Pointer; uncomprLen: LongInt); +var err: Integer; + d_stream: z_stream; (* decompression stream *) +begin + StrCopy(PChar(uncompr), 'garbage'); + + d_stream.zalloc := NIL; + d_stream.zfree := NIL; + d_stream.opaque := NIL; + + d_stream.next_in := compr; + d_stream.avail_in := Integer(comprLen); + + err := inflateInit(d_stream); + CHECK_ERR(err, 'inflateInit'); + + d_stream.next_out := uncompr; + d_stream.avail_out := Integer(uncomprLen); + + while TRUE do + begin + err := inflate(d_stream, Z_NO_FLUSH); + if err = Z_STREAM_END then + break; + if err = Z_NEED_DICT then + begin + if d_stream.adler <> dictId then + EXIT_ERR('unexpected dictionary'); + err := inflateSetDictionary(d_stream, dictionary, StrLen(dictionary)); + end; + CHECK_ERR(err, 'inflate with dict'); + end; + + err := inflateEnd(d_stream); + CHECK_ERR(err, 'inflateEnd'); + + if StrComp(PChar(uncompr), hello) <> 0 then + EXIT_ERR('bad inflate with dict') + else + WriteLn('inflate with dictionary: ', PChar(uncompr)); +end; +{$ENDIF} + +var compr, uncompr: Pointer; + comprLen, uncomprLen: LongInt; + +begin + if zlibVersion^ <> ZLIB_VERSION[1] then + EXIT_ERR('Incompatible zlib version'); + + WriteLn('zlib version: ', zlibVersion); + WriteLn('zlib compile flags: ', Format('0x%x', [zlibCompileFlags])); + + comprLen := 10000 * SizeOf(Integer); (* don't overflow on MSDOS *) + uncomprLen := comprLen; + GetMem(compr, comprLen); + GetMem(uncompr, uncomprLen); + if (compr = NIL) or (uncompr = NIL) then + EXIT_ERR('Out of memory'); + (* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + *) + FillChar(compr^, comprLen, 0); + FillChar(uncompr^, uncomprLen, 0); + + {$IFDEF TEST_COMPRESS} + WriteLn('** Testing compress'); + test_compress(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_GZIO} + WriteLn('** Testing gzio'); + if ParamCount >= 1 then + test_gzio(ParamStr(1), uncompr, uncomprLen) + else + test_gzio(TESTFILE, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_DEFLATE} + WriteLn('** Testing deflate with small buffers'); + test_deflate(compr, comprLen); + {$ENDIF} + {$IFDEF TEST_INFLATE} + WriteLn('** Testing inflate with small buffers'); + test_inflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_DEFLATE} + WriteLn('** Testing deflate with large buffers'); + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + {$IFDEF TEST_INFLATE} + WriteLn('** Testing inflate with large buffers'); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + {$IFDEF TEST_FLUSH} + WriteLn('** Testing deflate with full flush'); + test_flush(compr, comprLen); + {$ENDIF} + {$IFDEF TEST_SYNC} + WriteLn('** Testing inflateSync'); + test_sync(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + comprLen := uncomprLen; + + {$IFDEF TEST_DICT} + WriteLn('** Testing deflate and inflate with preset dictionary'); + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + {$ENDIF} + + FreeMem(compr, comprLen); + FreeMem(uncompr, uncomprLen); +end. diff --git a/test/zlib/zlib-1.2.8/contrib/pascal/readme.txt b/test/zlib/zlib-1.2.8/contrib/pascal/readme.txt new file mode 100644 index 000000000..60e87c8a3 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/pascal/readme.txt @@ -0,0 +1,76 @@ + +This directory contains a Pascal (Delphi, Kylix) interface to the +zlib data compression library. + + +Directory listing +================= + +zlibd32.mak makefile for Borland C++ +example.pas usage example of zlib +zlibpas.pas the Pascal interface to zlib +readme.txt this file + + +Compatibility notes +=================== + +- Although the name "zlib" would have been more normal for the + zlibpas unit, this name is already taken by Borland's ZLib unit. + This is somehow unfortunate, because that unit is not a genuine + interface to the full-fledged zlib functionality, but a suite of + class wrappers around zlib streams. Other essential features, + such as checksums, are missing. + It would have been more appropriate for that unit to have a name + like "ZStreams", or something similar. + +- The C and zlib-supplied types int, uInt, long, uLong, etc. are + translated directly into Pascal types of similar sizes (Integer, + LongInt, etc.), to avoid namespace pollution. In particular, + there is no conversion of unsigned int into a Pascal unsigned + integer. The Word type is non-portable and has the same size + (16 bits) both in a 16-bit and in a 32-bit environment, unlike + Integer. Even if there is a 32-bit Cardinal type, there is no + real need for unsigned int in zlib under a 32-bit environment. + +- Except for the callbacks, the zlib function interfaces are + assuming the calling convention normally used in Pascal + (__pascal for DOS and Windows16, __fastcall for Windows32). + Since the cdecl keyword is used, the old Turbo Pascal does + not work with this interface. + +- The gz* function interfaces are not translated, to avoid + interfacing problems with the C runtime library. Besides, + gzprintf(gzFile file, const char *format, ...) + cannot be translated into Pascal. + + +Legal issues +============ + +The zlibpas interface is: + Copyright (C) 1995-2003 Jean-loup Gailly and Mark Adler. + Copyright (C) 1998 by Bob Dellaca. + Copyright (C) 2003 by Cosmin Truta. + +The example program is: + Copyright (C) 1995-2003 by Jean-loup Gailly. + Copyright (C) 1998,1999,2000 by Jacques Nomssi Nzali. + Copyright (C) 2003 by Cosmin Truta. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + diff --git a/test/zlib/zlib-1.2.8/contrib/pascal/zlibd32.mak b/test/zlib/zlib-1.2.8/contrib/pascal/zlibd32.mak new file mode 100644 index 000000000..9bb00b7cc --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/pascal/zlibd32.mak @@ -0,0 +1,99 @@ +# Makefile for zlib +# For use with Delphi and C++ Builder under Win32 +# Updated for zlib 1.2.x by Cosmin Truta + +# ------------ Borland C++ ------------ + +# This project uses the Delphi (fastcall/register) calling convention: +LOC = -DZEXPORT=__fastcall -DZEXPORTVA=__cdecl + +CC = bcc32 +LD = bcc32 +AR = tlib +# do not use "-pr" in CFLAGS +CFLAGS = -a -d -k- -O2 $(LOC) +LDFLAGS = + + +# variables +ZLIB_LIB = zlib.lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj +OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: test/example.c zlib.h zconf.h + +minigzip.obj: test/minigzip.c zlib.h zconf.h + + +# For the sake of the old Borland make, +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + + +# cleanup +clean: + -del *.obj + -del *.exe + -del *.lib + -del *.tds + -del zlib.bak + -del foo.gz + diff --git a/test/zlib/zlib-1.2.8/contrib/pascal/zlibpas.pas b/test/zlib/zlib-1.2.8/contrib/pascal/zlibpas.pas new file mode 100644 index 000000000..e6a0782b4 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/pascal/zlibpas.pas @@ -0,0 +1,276 @@ +(* zlibpas -- Pascal interface to the zlib data compression library + * + * Copyright (C) 2003 Cosmin Truta. + * Derived from original sources by Bob Dellaca. + * For conditions of distribution and use, see copyright notice in readme.txt + *) + +unit zlibpas; + +interface + +const + ZLIB_VERSION = '1.2.8'; + ZLIB_VERNUM = $1280; + +type + alloc_func = function(opaque: Pointer; items, size: Integer): Pointer; + cdecl; + free_func = procedure(opaque, address: Pointer); + cdecl; + + in_func = function(opaque: Pointer; var buf: PByte): Integer; + cdecl; + out_func = function(opaque: Pointer; buf: PByte; size: Integer): Integer; + cdecl; + + z_streamp = ^z_stream; + z_stream = packed record + next_in: PChar; (* next input byte *) + avail_in: Integer; (* number of bytes available at next_in *) + total_in: LongInt; (* total nb of input bytes read so far *) + + next_out: PChar; (* next output byte should be put there *) + avail_out: Integer; (* remaining free space at next_out *) + total_out: LongInt; (* total nb of bytes output so far *) + + msg: PChar; (* last error message, NULL if no error *) + state: Pointer; (* not visible by applications *) + + zalloc: alloc_func; (* used to allocate the internal state *) + zfree: free_func; (* used to free the internal state *) + opaque: Pointer; (* private data object passed to zalloc and zfree *) + + data_type: Integer; (* best guess about the data type: ascii or binary *) + adler: LongInt; (* adler32 value of the uncompressed data *) + reserved: LongInt; (* reserved for future use *) + end; + + gz_headerp = ^gz_header; + gz_header = packed record + text: Integer; (* true if compressed data believed to be text *) + time: LongInt; (* modification time *) + xflags: Integer; (* extra flags (not used when writing a gzip file) *) + os: Integer; (* operating system *) + extra: PChar; (* pointer to extra field or Z_NULL if none *) + extra_len: Integer; (* extra field length (valid if extra != Z_NULL) *) + extra_max: Integer; (* space at extra (only when reading header) *) + name: PChar; (* pointer to zero-terminated file name or Z_NULL *) + name_max: Integer; (* space at name (only when reading header) *) + comment: PChar; (* pointer to zero-terminated comment or Z_NULL *) + comm_max: Integer; (* space at comment (only when reading header) *) + hcrc: Integer; (* true if there was or will be a header crc *) + done: Integer; (* true when done reading gzip header *) + end; + +(* constants *) +const + Z_NO_FLUSH = 0; + Z_PARTIAL_FLUSH = 1; + Z_SYNC_FLUSH = 2; + Z_FULL_FLUSH = 3; + Z_FINISH = 4; + Z_BLOCK = 5; + Z_TREES = 6; + + Z_OK = 0; + Z_STREAM_END = 1; + Z_NEED_DICT = 2; + Z_ERRNO = -1; + Z_STREAM_ERROR = -2; + Z_DATA_ERROR = -3; + Z_MEM_ERROR = -4; + Z_BUF_ERROR = -5; + Z_VERSION_ERROR = -6; + + Z_NO_COMPRESSION = 0; + Z_BEST_SPEED = 1; + Z_BEST_COMPRESSION = 9; + Z_DEFAULT_COMPRESSION = -1; + + Z_FILTERED = 1; + Z_HUFFMAN_ONLY = 2; + Z_RLE = 3; + Z_FIXED = 4; + Z_DEFAULT_STRATEGY = 0; + + Z_BINARY = 0; + Z_TEXT = 1; + Z_ASCII = 1; + Z_UNKNOWN = 2; + + Z_DEFLATED = 8; + +(* basic functions *) +function zlibVersion: PChar; +function deflateInit(var strm: z_stream; level: Integer): Integer; +function deflate(var strm: z_stream; flush: Integer): Integer; +function deflateEnd(var strm: z_stream): Integer; +function inflateInit(var strm: z_stream): Integer; +function inflate(var strm: z_stream; flush: Integer): Integer; +function inflateEnd(var strm: z_stream): Integer; + +(* advanced functions *) +function deflateInit2(var strm: z_stream; level, method, windowBits, + memLevel, strategy: Integer): Integer; +function deflateSetDictionary(var strm: z_stream; const dictionary: PChar; + dictLength: Integer): Integer; +function deflateCopy(var dest, source: z_stream): Integer; +function deflateReset(var strm: z_stream): Integer; +function deflateParams(var strm: z_stream; level, strategy: Integer): Integer; +function deflateTune(var strm: z_stream; good_length, max_lazy, nice_length, max_chain: Integer): Integer; +function deflateBound(var strm: z_stream; sourceLen: LongInt): LongInt; +function deflatePending(var strm: z_stream; var pending: Integer; var bits: Integer): Integer; +function deflatePrime(var strm: z_stream; bits, value: Integer): Integer; +function deflateSetHeader(var strm: z_stream; head: gz_header): Integer; +function inflateInit2(var strm: z_stream; windowBits: Integer): Integer; +function inflateSetDictionary(var strm: z_stream; const dictionary: PChar; + dictLength: Integer): Integer; +function inflateSync(var strm: z_stream): Integer; +function inflateCopy(var dest, source: z_stream): Integer; +function inflateReset(var strm: z_stream): Integer; +function inflateReset2(var strm: z_stream; windowBits: Integer): Integer; +function inflatePrime(var strm: z_stream; bits, value: Integer): Integer; +function inflateMark(var strm: z_stream): LongInt; +function inflateGetHeader(var strm: z_stream; var head: gz_header): Integer; +function inflateBackInit(var strm: z_stream; + windowBits: Integer; window: PChar): Integer; +function inflateBack(var strm: z_stream; in_fn: in_func; in_desc: Pointer; + out_fn: out_func; out_desc: Pointer): Integer; +function inflateBackEnd(var strm: z_stream): Integer; +function zlibCompileFlags: LongInt; + +(* utility functions *) +function compress(dest: PChar; var destLen: LongInt; + const source: PChar; sourceLen: LongInt): Integer; +function compress2(dest: PChar; var destLen: LongInt; + const source: PChar; sourceLen: LongInt; + level: Integer): Integer; +function compressBound(sourceLen: LongInt): LongInt; +function uncompress(dest: PChar; var destLen: LongInt; + const source: PChar; sourceLen: LongInt): Integer; + +(* checksum functions *) +function adler32(adler: LongInt; const buf: PChar; len: Integer): LongInt; +function adler32_combine(adler1, adler2, len2: LongInt): LongInt; +function crc32(crc: LongInt; const buf: PChar; len: Integer): LongInt; +function crc32_combine(crc1, crc2, len2: LongInt): LongInt; + +(* various hacks, don't look :) *) +function deflateInit_(var strm: z_stream; level: Integer; + const version: PChar; stream_size: Integer): Integer; +function inflateInit_(var strm: z_stream; const version: PChar; + stream_size: Integer): Integer; +function deflateInit2_(var strm: z_stream; + level, method, windowBits, memLevel, strategy: Integer; + const version: PChar; stream_size: Integer): Integer; +function inflateInit2_(var strm: z_stream; windowBits: Integer; + const version: PChar; stream_size: Integer): Integer; +function inflateBackInit_(var strm: z_stream; + windowBits: Integer; window: PChar; + const version: PChar; stream_size: Integer): Integer; + + +implementation + +{$L adler32.obj} +{$L compress.obj} +{$L crc32.obj} +{$L deflate.obj} +{$L infback.obj} +{$L inffast.obj} +{$L inflate.obj} +{$L inftrees.obj} +{$L trees.obj} +{$L uncompr.obj} +{$L zutil.obj} + +function adler32; external; +function adler32_combine; external; +function compress; external; +function compress2; external; +function compressBound; external; +function crc32; external; +function crc32_combine; external; +function deflate; external; +function deflateBound; external; +function deflateCopy; external; +function deflateEnd; external; +function deflateInit_; external; +function deflateInit2_; external; +function deflateParams; external; +function deflatePending; external; +function deflatePrime; external; +function deflateReset; external; +function deflateSetDictionary; external; +function deflateSetHeader; external; +function deflateTune; external; +function inflate; external; +function inflateBack; external; +function inflateBackEnd; external; +function inflateBackInit_; external; +function inflateCopy; external; +function inflateEnd; external; +function inflateGetHeader; external; +function inflateInit_; external; +function inflateInit2_; external; +function inflateMark; external; +function inflatePrime; external; +function inflateReset; external; +function inflateReset2; external; +function inflateSetDictionary; external; +function inflateSync; external; +function uncompress; external; +function zlibCompileFlags; external; +function zlibVersion; external; + +function deflateInit(var strm: z_stream; level: Integer): Integer; +begin + Result := deflateInit_(strm, level, ZLIB_VERSION, sizeof(z_stream)); +end; + +function deflateInit2(var strm: z_stream; level, method, windowBits, memLevel, + strategy: Integer): Integer; +begin + Result := deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + ZLIB_VERSION, sizeof(z_stream)); +end; + +function inflateInit(var strm: z_stream): Integer; +begin + Result := inflateInit_(strm, ZLIB_VERSION, sizeof(z_stream)); +end; + +function inflateInit2(var strm: z_stream; windowBits: Integer): Integer; +begin + Result := inflateInit2_(strm, windowBits, ZLIB_VERSION, sizeof(z_stream)); +end; + +function inflateBackInit(var strm: z_stream; + windowBits: Integer; window: PChar): Integer; +begin + Result := inflateBackInit_(strm, windowBits, window, + ZLIB_VERSION, sizeof(z_stream)); +end; + +function _malloc(Size: Integer): Pointer; cdecl; +begin + GetMem(Result, Size); +end; + +procedure _free(Block: Pointer); cdecl; +begin + FreeMem(Block); +end; + +procedure _memset(P: Pointer; B: Byte; count: Integer); cdecl; +begin + FillChar(P^, count, B); +end; + +procedure _memcpy(dest, source: Pointer; count: Integer); cdecl; +begin + Move(source^, dest^, count); +end; + +end. diff --git a/test/zlib/zlib-1.2.8/contrib/puff/Makefile b/test/zlib/zlib-1.2.8/contrib/puff/Makefile new file mode 100644 index 000000000..0e2594c80 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/puff/Makefile @@ -0,0 +1,42 @@ +CFLAGS=-O + +puff: puff.o pufftest.o + +puff.o: puff.h + +pufftest.o: puff.h + +test: puff + puff zeros.raw + +puft: puff.c puff.h pufftest.o + cc -fprofile-arcs -ftest-coverage -o puft puff.c pufftest.o + +# puff full coverage test (should say 100%) +cov: puft + @rm -f *.gcov *.gcda + @puft -w zeros.raw 2>&1 | cat > /dev/null + @echo '04' | xxd -r -p | puft 2> /dev/null || test $$? -eq 2 + @echo '00' | xxd -r -p | puft 2> /dev/null || test $$? -eq 2 + @echo '00 00 00 00 00' | xxd -r -p | puft 2> /dev/null || test $$? -eq 254 + @echo '00 01 00 fe ff' | xxd -r -p | puft 2> /dev/null || test $$? -eq 2 + @echo '01 01 00 fe ff 0a' | xxd -r -p | puft -f 2>&1 | cat > /dev/null + @echo '02 7e ff ff' | xxd -r -p | puft 2> /dev/null || test $$? -eq 246 + @echo '02' | xxd -r -p | puft 2> /dev/null || test $$? -eq 2 + @echo '04 80 49 92 24 49 92 24 0f b4 ff ff c3 04' | xxd -r -p | puft 2> /dev/null || test $$? -eq 2 + @echo '04 80 49 92 24 49 92 24 71 ff ff 93 11 00' | xxd -r -p | puft 2> /dev/null || test $$? -eq 249 + @echo '04 c0 81 08 00 00 00 00 20 7f eb 0b 00 00' | xxd -r -p | puft 2> /dev/null || test $$? -eq 246 + @echo '0b 00 00' | xxd -r -p | puft -f 2>&1 | cat > /dev/null + @echo '1a 07' | xxd -r -p | puft 2> /dev/null || test $$? -eq 246 + @echo '0c c0 81 00 00 00 00 00 90 ff 6b 04' | xxd -r -p | puft 2> /dev/null || test $$? -eq 245 + @puft -f zeros.raw 2>&1 | cat > /dev/null + @echo 'fc 00 00' | xxd -r -p | puft 2> /dev/null || test $$? -eq 253 + @echo '04 00 fe ff' | xxd -r -p | puft 2> /dev/null || test $$? -eq 252 + @echo '04 00 24 49' | xxd -r -p | puft 2> /dev/null || test $$? -eq 251 + @echo '04 80 49 92 24 49 92 24 0f b4 ff ff c3 84' | xxd -r -p | puft 2> /dev/null || test $$? -eq 248 + @echo '04 00 24 e9 ff ff' | xxd -r -p | puft 2> /dev/null || test $$? -eq 250 + @echo '04 00 24 e9 ff 6d' | xxd -r -p | puft 2> /dev/null || test $$? -eq 247 + @gcov -n puff.c + +clean: + rm -f puff puft *.o *.gc* diff --git a/test/zlib/zlib-1.2.8/contrib/puff/README b/test/zlib/zlib-1.2.8/contrib/puff/README new file mode 100644 index 000000000..bbc4cb595 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/puff/README @@ -0,0 +1,63 @@ +Puff -- A Simple Inflate +3 Mar 2003 +Mark Adler +madler@alumni.caltech.edu + +What this is -- + +puff.c provides the routine puff() to decompress the deflate data format. It +does so more slowly than zlib, but the code is about one-fifth the size of the +inflate code in zlib, and written to be very easy to read. + +Why I wrote this -- + +puff.c was written to document the deflate format unambiguously, by virtue of +being working C code. It is meant to supplement RFC 1951, which formally +describes the deflate format. I have received many questions on details of the +deflate format, and I hope that reading this code will answer those questions. +puff.c is heavily commented with details of the deflate format, especially +those little nooks and cranies of the format that might not be obvious from a +specification. + +puff.c may also be useful in applications where code size or memory usage is a +very limited resource, and speed is not as important. + +How to use it -- + +Well, most likely you should just be reading puff.c and using zlib for actual +applications, but if you must ... + +Include puff.h in your code, which provides this prototype: + +int puff(unsigned char *dest, /* pointer to destination pointer */ + unsigned long *destlen, /* amount of output space */ + unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen); /* amount of input available */ + +Then you can call puff() to decompress a deflate stream that is in memory in +its entirety at source, to a sufficiently sized block of memory for the +decompressed data at dest. puff() is the only external symbol in puff.c The +only C library functions that puff.c needs are setjmp() and longjmp(), which +are used to simplify error checking in the code to improve readabilty. puff.c +does no memory allocation, and uses less than 2K bytes off of the stack. + +If destlen is not enough space for the uncompressed data, then inflate will +return an error without writing more than destlen bytes. Note that this means +that in order to decompress the deflate data successfully, you need to know +the size of the uncompressed data ahead of time. + +If needed, puff() can determine the size of the uncompressed data with no +output space. This is done by passing dest equal to (unsigned char *)0. Then +the initial value of *destlen is ignored and *destlen is set to the length of +the uncompressed data. So if the size of the uncompressed data is not known, +then two passes of puff() can be used--first to determine the size, and second +to do the actual inflation after allocating the appropriate memory. Not +pretty, but it works. (This is one of the reasons you should be using zlib.) + +The deflate format is self-terminating. If the deflate stream does not end +in *sourcelen bytes, puff() will return an error without reading at or past +endsource. + +On return, *sourcelen is updated to the amount of input data consumed, and +*destlen is updated to the size of the uncompressed data. See the comments +in puff.c for the possible return codes for puff(). diff --git a/test/zlib/zlib-1.2.8/contrib/puff/puff.c b/test/zlib/zlib-1.2.8/contrib/puff/puff.c new file mode 100644 index 000000000..ba58483d5 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/puff/puff.c @@ -0,0 +1,840 @@ +/* + * puff.c + * Copyright (C) 2002-2013 Mark Adler + * For conditions of distribution and use, see copyright notice in puff.h + * version 2.3, 21 Jan 2013 + * + * puff.c is a simple inflate written to be an unambiguous way to specify the + * deflate format. It is not written for speed but rather simplicity. As a + * side benefit, this code might actually be useful when small code is more + * important than speed, such as bootstrap applications. For typical deflate + * data, zlib's inflate() is about four times as fast as puff(). zlib's + * inflate compiles to around 20K on my machine, whereas puff.c compiles to + * around 4K on my machine (a PowerPC using GNU cc). If the faster decode() + * function here is used, then puff() is only twice as slow as zlib's + * inflate(). + * + * All dynamically allocated memory comes from the stack. The stack required + * is less than 2K bytes. This code is compatible with 16-bit int's and + * assumes that long's are at least 32 bits. puff.c uses the short data type, + * assumed to be 16 bits, for arrays in order to to conserve memory. The code + * works whether integers are stored big endian or little endian. + * + * In the comments below are "Format notes" that describe the inflate process + * and document some of the less obvious aspects of the format. This source + * code is meant to supplement RFC 1951, which formally describes the deflate + * format: + * + * http://www.zlib.org/rfc-deflate.html + */ + +/* + * Change history: + * + * 1.0 10 Feb 2002 - First version + * 1.1 17 Feb 2002 - Clarifications of some comments and notes + * - Update puff() dest and source pointers on negative + * errors to facilitate debugging deflators + * - Remove longest from struct huffman -- not needed + * - Simplify offs[] index in construct() + * - Add input size and checking, using longjmp() to + * maintain easy readability + * - Use short data type for large arrays + * - Use pointers instead of long to specify source and + * destination sizes to avoid arbitrary 4 GB limits + * 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!), + * but leave simple version for readabilty + * - Make sure invalid distances detected if pointers + * are 16 bits + * - Fix fixed codes table error + * - Provide a scanning mode for determining size of + * uncompressed data + * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Gailly] + * - Add a puff.h file for the interface + * - Add braces in puff() for else do [Gailly] + * - Use indexes instead of pointers for readability + * 1.4 31 Mar 2002 - Simplify construct() code set check + * - Fix some comments + * - Add FIXLCODES #define + * 1.5 6 Apr 2002 - Minor comment fixes + * 1.6 7 Aug 2002 - Minor format changes + * 1.7 3 Mar 2003 - Added test code for distribution + * - Added zlib-like license + * 1.8 9 Jan 2004 - Added some comments on no distance codes case + * 1.9 21 Feb 2008 - Fix bug on 16-bit integer architectures [Pohland] + * - Catch missing end-of-block symbol error + * 2.0 25 Jul 2008 - Add #define to permit distance too far back + * - Add option in TEST code for puff to write the data + * - Add option in TEST code to skip input bytes + * - Allow TEST code to read from piped stdin + * 2.1 4 Apr 2010 - Avoid variable initialization for happier compilers + * - Avoid unsigned comparisons for even happier compilers + * 2.2 25 Apr 2010 - Fix bug in variable initializations [Oberhumer] + * - Add const where appropriate [Oberhumer] + * - Split if's and ?'s for coverage testing + * - Break out test code to separate file + * - Move NIL to puff.h + * - Allow incomplete code only if single code length is 1 + * - Add full code coverage test to Makefile + * 2.3 21 Jan 2013 - Check for invalid code length codes in dynamic blocks + */ + +#include /* for setjmp(), longjmp(), and jmp_buf */ +#include "puff.h" /* prototype for puff() */ + +#define local static /* for local function definitions */ + +/* + * Maximums for allocations and loops. It is not useful to change these -- + * they are fixed by the deflate format. + */ +#define MAXBITS 15 /* maximum bits in a code */ +#define MAXLCODES 286 /* maximum number of literal/length codes */ +#define MAXDCODES 30 /* maximum number of distance codes */ +#define MAXCODES (MAXLCODES+MAXDCODES) /* maximum codes lengths to read */ +#define FIXLCODES 288 /* number of fixed literal/length codes */ + +/* input and output state */ +struct state { + /* output state */ + unsigned char *out; /* output buffer */ + unsigned long outlen; /* available space at out */ + unsigned long outcnt; /* bytes written to out so far */ + + /* input state */ + const unsigned char *in; /* input buffer */ + unsigned long inlen; /* available input at in */ + unsigned long incnt; /* bytes read so far */ + int bitbuf; /* bit buffer */ + int bitcnt; /* number of bits in bit buffer */ + + /* input limit error return state for bits() and decode() */ + jmp_buf env; +}; + +/* + * Return need bits from the input stream. This always leaves less than + * eight bits in the buffer. bits() works properly for need == 0. + * + * Format notes: + * + * - Bits are stored in bytes from the least significant bit to the most + * significant bit. Therefore bits are dropped from the bottom of the bit + * buffer, using shift right, and new bytes are appended to the top of the + * bit buffer, using shift left. + */ +local int bits(struct state *s, int need) +{ + long val; /* bit accumulator (can use up to 20 bits) */ + + /* load at least need bits into val */ + val = s->bitbuf; + while (s->bitcnt < need) { + if (s->incnt == s->inlen) + longjmp(s->env, 1); /* out of input */ + val |= (long)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */ + s->bitcnt += 8; + } + + /* drop need bits and update buffer, always zero to seven bits left */ + s->bitbuf = (int)(val >> need); + s->bitcnt -= need; + + /* return need bits, zeroing the bits above that */ + return (int)(val & ((1L << need) - 1)); +} + +/* + * Process a stored block. + * + * Format notes: + * + * - After the two-bit stored block type (00), the stored block length and + * stored bytes are byte-aligned for fast copying. Therefore any leftover + * bits in the byte that has the last bit of the type, as many as seven, are + * discarded. The value of the discarded bits are not defined and should not + * be checked against any expectation. + * + * - The second inverted copy of the stored block length does not have to be + * checked, but it's probably a good idea to do so anyway. + * + * - A stored block can have zero length. This is sometimes used to byte-align + * subsets of the compressed data for random access or partial recovery. + */ +local int stored(struct state *s) +{ + unsigned len; /* length of stored block */ + + /* discard leftover bits from current byte (assumes s->bitcnt < 8) */ + s->bitbuf = 0; + s->bitcnt = 0; + + /* get length and check against its one's complement */ + if (s->incnt + 4 > s->inlen) + return 2; /* not enough input */ + len = s->in[s->incnt++]; + len |= s->in[s->incnt++] << 8; + if (s->in[s->incnt++] != (~len & 0xff) || + s->in[s->incnt++] != ((~len >> 8) & 0xff)) + return -2; /* didn't match complement! */ + + /* copy len bytes from in to out */ + if (s->incnt + len > s->inlen) + return 2; /* not enough input */ + if (s->out != NIL) { + if (s->outcnt + len > s->outlen) + return 1; /* not enough output space */ + while (len--) + s->out[s->outcnt++] = s->in[s->incnt++]; + } + else { /* just scanning */ + s->outcnt += len; + s->incnt += len; + } + + /* done with a valid stored block */ + return 0; +} + +/* + * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of + * each length, which for a canonical code are stepped through in order. + * symbol[] are the symbol values in canonical order, where the number of + * entries is the sum of the counts in count[]. The decoding process can be + * seen in the function decode() below. + */ +struct huffman { + short *count; /* number of symbols of each length */ + short *symbol; /* canonically ordered symbols */ +}; + +/* + * Decode a code from the stream s using huffman table h. Return the symbol or + * a negative value if there is an error. If all of the lengths are zero, i.e. + * an empty code, or if the code is incomplete and an invalid code is received, + * then -10 is returned after reading MAXBITS bits. + * + * Format notes: + * + * - The codes as stored in the compressed data are bit-reversed relative to + * a simple integer ordering of codes of the same lengths. Hence below the + * bits are pulled from the compressed data one at a time and used to + * build the code value reversed from what is in the stream in order to + * permit simple integer comparisons for decoding. A table-based decoding + * scheme (as used in zlib) does not need to do this reversal. + * + * - The first code for the shortest length is all zeros. Subsequent codes of + * the same length are simply integer increments of the previous code. When + * moving up a length, a zero bit is appended to the code. For a complete + * code, the last code of the longest length will be all ones. + * + * - Incomplete codes are handled by this decoder, since they are permitted + * in the deflate format. See the format notes for fixed() and dynamic(). + */ +#ifdef SLOW +local int decode(struct state *s, const struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + + code = first = index = 0; + for (len = 1; len <= MAXBITS; len++) { + code |= bits(s, 1); /* get next bit */ + count = h->count[len]; + if (code - count < first) /* if length len, return symbol */ + return h->symbol[index + (code - first)]; + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + } + return -10; /* ran out of codes */ +} + +/* + * A faster version of decode() for real applications of this code. It's not + * as readable, but it makes puff() twice as fast. And it only makes the code + * a few percent larger. + */ +#else /* !SLOW */ +local int decode(struct state *s, const struct huffman *h) +{ + int len; /* current number of bits in code */ + int code; /* len bits being decoded */ + int first; /* first code of length len */ + int count; /* number of codes of length len */ + int index; /* index of first code of length len in symbol table */ + int bitbuf; /* bits from stream */ + int left; /* bits left in next or left to process */ + short *next; /* next number of codes */ + + bitbuf = s->bitbuf; + left = s->bitcnt; + code = first = index = 0; + len = 1; + next = h->count + 1; + while (1) { + while (left--) { + code |= bitbuf & 1; + bitbuf >>= 1; + count = *next++; + if (code - count < first) { /* if length len, return symbol */ + s->bitbuf = bitbuf; + s->bitcnt = (s->bitcnt - len) & 7; + return h->symbol[index + (code - first)]; + } + index += count; /* else update for next length */ + first += count; + first <<= 1; + code <<= 1; + len++; + } + left = (MAXBITS+1) - len; + if (left == 0) + break; + if (s->incnt == s->inlen) + longjmp(s->env, 1); /* out of input */ + bitbuf = s->in[s->incnt++]; + if (left > 8) + left = 8; + } + return -10; /* ran out of codes */ +} +#endif /* SLOW */ + +/* + * Given the list of code lengths length[0..n-1] representing a canonical + * Huffman code for n symbols, construct the tables required to decode those + * codes. Those tables are the number of codes of each length, and the symbols + * sorted by length, retaining their original order within each length. The + * return value is zero for a complete code set, negative for an over- + * subscribed code set, and positive for an incomplete code set. The tables + * can be used if the return value is zero or positive, but they cannot be used + * if the return value is negative. If the return value is zero, it is not + * possible for decode() using that table to return an error--any stream of + * enough bits will resolve to a symbol. If the return value is positive, then + * it is possible for decode() using that table to return an error for received + * codes past the end of the incomplete lengths. + * + * Not used by decode(), but used for error checking, h->count[0] is the number + * of the n symbols not in the code. So n - h->count[0] is the number of + * codes. This is useful for checking for incomplete codes that have more than + * one symbol, which is an error in a dynamic block. + * + * Assumption: for all i in 0..n-1, 0 <= length[i] <= MAXBITS + * This is assured by the construction of the length arrays in dynamic() and + * fixed() and is not verified by construct(). + * + * Format notes: + * + * - Permitted and expected examples of incomplete codes are one of the fixed + * codes and any code with a single symbol which in deflate is coded as one + * bit instead of zero bits. See the format notes for fixed() and dynamic(). + * + * - Within a given code length, the symbols are kept in ascending order for + * the code bits definition. + */ +local int construct(struct huffman *h, const short *length, int n) +{ + int symbol; /* current symbol when stepping through length[] */ + int len; /* current length when stepping through h->count[] */ + int left; /* number of possible codes left of current length */ + short offs[MAXBITS+1]; /* offsets in symbol table for each length */ + + /* count number of codes of each length */ + for (len = 0; len <= MAXBITS; len++) + h->count[len] = 0; + for (symbol = 0; symbol < n; symbol++) + (h->count[length[symbol]])++; /* assumes lengths are within bounds */ + if (h->count[0] == n) /* no codes! */ + return 0; /* complete, but decode() will fail */ + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; /* one possible code of zero length */ + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; /* one more bit, double codes left */ + left -= h->count[len]; /* deduct count from possible codes */ + if (left < 0) + return left; /* over-subscribed--return negative */ + } /* left > 0 means incomplete */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + h->count[len]; + + /* + * put symbols in table sorted by length, by symbol order within each + * length + */ + for (symbol = 0; symbol < n; symbol++) + if (length[symbol] != 0) + h->symbol[offs[length[symbol]]++] = symbol; + + /* return zero for complete set, positive for incomplete set */ + return left; +} + +/* + * Decode literal/length and distance codes until an end-of-block code. + * + * Format notes: + * + * - Compressed data that is after the block type if fixed or after the code + * description if dynamic is a combination of literals and length/distance + * pairs terminated by and end-of-block code. Literals are simply Huffman + * coded bytes. A length/distance pair is a coded length followed by a + * coded distance to represent a string that occurs earlier in the + * uncompressed data that occurs again at the current location. + * + * - Literals, lengths, and the end-of-block code are combined into a single + * code of up to 286 symbols. They are 256 literals (0..255), 29 length + * symbols (257..285), and the end-of-block symbol (256). + * + * - There are 256 possible lengths (3..258), and so 29 symbols are not enough + * to represent all of those. Lengths 3..10 and 258 are in fact represented + * by just a length symbol. Lengths 11..257 are represented as a symbol and + * some number of extra bits that are added as an integer to the base length + * of the length symbol. The number of extra bits is determined by the base + * length symbol. These are in the static arrays below, lens[] for the base + * lengths and lext[] for the corresponding number of extra bits. + * + * - The reason that 258 gets its own symbol is that the longest length is used + * often in highly redundant files. Note that 258 can also be coded as the + * base value 227 plus the maximum extra value of 31. While a good deflate + * should never do this, it is not an error, and should be decoded properly. + * + * - If a length is decoded, including its extra bits if any, then it is + * followed a distance code. There are up to 30 distance symbols. Again + * there are many more possible distances (1..32768), so extra bits are added + * to a base value represented by the symbol. The distances 1..4 get their + * own symbol, but the rest require extra bits. The base distances and + * corresponding number of extra bits are below in the static arrays dist[] + * and dext[]. + * + * - Literal bytes are simply written to the output. A length/distance pair is + * an instruction to copy previously uncompressed bytes to the output. The + * copy is from distance bytes back in the output stream, copying for length + * bytes. + * + * - Distances pointing before the beginning of the output data are not + * permitted. + * + * - Overlapped copies, where the length is greater than the distance, are + * allowed and common. For example, a distance of one and a length of 258 + * simply copies the last byte 258 times. A distance of four and a length of + * twelve copies the last four bytes three times. A simple forward copy + * ignoring whether the length is greater than the distance or not implements + * this correctly. You should not use memcpy() since its behavior is not + * defined for overlapped arrays. You should not use memmove() or bcopy() + * since though their behavior -is- defined for overlapping arrays, it is + * defined to do the wrong thing in this case. + */ +local int codes(struct state *s, + const struct huffman *lencode, + const struct huffman *distcode) +{ + int symbol; /* decoded symbol */ + int len; /* length for copy */ + unsigned dist; /* distance for copy */ + static const short lens[29] = { /* Size base for length codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; + static const short lext[29] = { /* Extra bits for length codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; + static const short dists[30] = { /* Offset base for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; + static const short dext[30] = { /* Extra bits for distance codes 0..29 */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + /* decode literals and length/distance pairs */ + do { + symbol = decode(s, lencode); + if (symbol < 0) + return symbol; /* invalid symbol */ + if (symbol < 256) { /* literal: symbol is the byte */ + /* write out the literal */ + if (s->out != NIL) { + if (s->outcnt == s->outlen) + return 1; + s->out[s->outcnt] = symbol; + } + s->outcnt++; + } + else if (symbol > 256) { /* length */ + /* get and compute length */ + symbol -= 257; + if (symbol >= 29) + return -10; /* invalid fixed code */ + len = lens[symbol] + bits(s, lext[symbol]); + + /* get and check distance */ + symbol = decode(s, distcode); + if (symbol < 0) + return symbol; /* invalid symbol */ + dist = dists[symbol] + bits(s, dext[symbol]); +#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (dist > s->outcnt) + return -11; /* distance too far back */ +#endif + + /* copy length bytes from distance bytes back */ + if (s->out != NIL) { + if (s->outcnt + len > s->outlen) + return 1; + while (len--) { + s->out[s->outcnt] = +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + dist > s->outcnt ? + 0 : +#endif + s->out[s->outcnt - dist]; + s->outcnt++; + } + } + else + s->outcnt += len; + } + } while (symbol != 256); /* end of block symbol */ + + /* done with a valid fixed or dynamic block */ + return 0; +} + +/* + * Process a fixed codes block. + * + * Format notes: + * + * - This block type can be useful for compressing small amounts of data for + * which the size of the code descriptions in a dynamic block exceeds the + * benefit of custom codes for that block. For fixed codes, no bits are + * spent on code descriptions. Instead the code lengths for literal/length + * codes and distance codes are fixed. The specific lengths for each symbol + * can be seen in the "for" loops below. + * + * - The literal/length code is complete, but has two symbols that are invalid + * and should result in an error if received. This cannot be implemented + * simply as an incomplete code since those two symbols are in the "middle" + * of the code. They are eight bits long and the longest literal/length\ + * code is nine bits. Therefore the code must be constructed with those + * symbols, and the invalid symbols must be detected after decoding. + * + * - The fixed distance codes also have two invalid symbols that should result + * in an error if received. Since all of the distance codes are the same + * length, this can be implemented as an incomplete code. Then the invalid + * codes are detected while decoding. + */ +local int fixed(struct state *s) +{ + static int virgin = 1; + static short lencnt[MAXBITS+1], lensym[FIXLCODES]; + static short distcnt[MAXBITS+1], distsym[MAXDCODES]; + static struct huffman lencode, distcode; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + int symbol; + short lengths[FIXLCODES]; + + /* construct lencode and distcode */ + lencode.count = lencnt; + lencode.symbol = lensym; + distcode.count = distcnt; + distcode.symbol = distsym; + + /* literal/length table */ + for (symbol = 0; symbol < 144; symbol++) + lengths[symbol] = 8; + for (; symbol < 256; symbol++) + lengths[symbol] = 9; + for (; symbol < 280; symbol++) + lengths[symbol] = 7; + for (; symbol < FIXLCODES; symbol++) + lengths[symbol] = 8; + construct(&lencode, lengths, FIXLCODES); + + /* distance table */ + for (symbol = 0; symbol < MAXDCODES; symbol++) + lengths[symbol] = 5; + construct(&distcode, lengths, MAXDCODES); + + /* do this just once */ + virgin = 0; + } + + /* decode data until end-of-block code */ + return codes(s, &lencode, &distcode); +} + +/* + * Process a dynamic codes block. + * + * Format notes: + * + * - A dynamic block starts with a description of the literal/length and + * distance codes for that block. New dynamic blocks allow the compressor to + * rapidly adapt to changing data with new codes optimized for that data. + * + * - The codes used by the deflate format are "canonical", which means that + * the actual bits of the codes are generated in an unambiguous way simply + * from the number of bits in each code. Therefore the code descriptions + * are simply a list of code lengths for each symbol. + * + * - The code lengths are stored in order for the symbols, so lengths are + * provided for each of the literal/length symbols, and for each of the + * distance symbols. + * + * - If a symbol is not used in the block, this is represented by a zero as + * as the code length. This does not mean a zero-length code, but rather + * that no code should be created for this symbol. There is no way in the + * deflate format to represent a zero-length code. + * + * - The maximum number of bits in a code is 15, so the possible lengths for + * any code are 1..15. + * + * - The fact that a length of zero is not permitted for a code has an + * interesting consequence. Normally if only one symbol is used for a given + * code, then in fact that code could be represented with zero bits. However + * in deflate, that code has to be at least one bit. So for example, if + * only a single distance base symbol appears in a block, then it will be + * represented by a single code of length one, in particular one 0 bit. This + * is an incomplete code, since if a 1 bit is received, it has no meaning, + * and should result in an error. So incomplete distance codes of one symbol + * should be permitted, and the receipt of invalid codes should be handled. + * + * - It is also possible to have a single literal/length code, but that code + * must be the end-of-block code, since every dynamic block has one. This + * is not the most efficient way to create an empty block (an empty fixed + * block is fewer bits), but it is allowed by the format. So incomplete + * literal/length codes of one symbol should also be permitted. + * + * - If there are only literal codes and no lengths, then there are no distance + * codes. This is represented by one distance code with zero bits. + * + * - The list of up to 286 length/literal lengths and up to 30 distance lengths + * are themselves compressed using Huffman codes and run-length encoding. In + * the list of code lengths, a 0 symbol means no code, a 1..15 symbol means + * that length, and the symbols 16, 17, and 18 are run-length instructions. + * Each of 16, 17, and 18 are follwed by extra bits to define the length of + * the run. 16 copies the last length 3 to 6 times. 17 represents 3 to 10 + * zero lengths, and 18 represents 11 to 138 zero lengths. Unused symbols + * are common, hence the special coding for zero lengths. + * + * - The symbols for 0..18 are Huffman coded, and so that code must be + * described first. This is simply a sequence of up to 19 three-bit values + * representing no code (0) or the code length for that symbol (1..7). + * + * - A dynamic block starts with three fixed-size counts from which is computed + * the number of literal/length code lengths, the number of distance code + * lengths, and the number of code length code lengths (ok, you come up with + * a better name!) in the code descriptions. For the literal/length and + * distance codes, lengths after those provided are considered zero, i.e. no + * code. The code length code lengths are received in a permuted order (see + * the order[] array below) to make a short code length code length list more + * likely. As it turns out, very short and very long codes are less likely + * to be seen in a dynamic code description, hence what may appear initially + * to be a peculiar ordering. + * + * - Given the number of literal/length code lengths (nlen) and distance code + * lengths (ndist), then they are treated as one long list of nlen + ndist + * code lengths. Therefore run-length coding can and often does cross the + * boundary between the two sets of lengths. + * + * - So to summarize, the code description at the start of a dynamic block is + * three counts for the number of code lengths for the literal/length codes, + * the distance codes, and the code length codes. This is followed by the + * code length code lengths, three bits each. This is used to construct the + * code length code which is used to read the remainder of the lengths. Then + * the literal/length code lengths and distance lengths are read as a single + * set of lengths using the code length codes. Codes are constructed from + * the resulting two sets of lengths, and then finally you can start + * decoding actual compressed data in the block. + * + * - For reference, a "typical" size for the code description in a dynamic + * block is around 80 bytes. + */ +local int dynamic(struct state *s) +{ + int nlen, ndist, ncode; /* number of lengths in descriptor */ + int index; /* index of lengths[] */ + int err; /* construct() return value */ + short lengths[MAXCODES]; /* descriptor code lengths */ + short lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */ + short distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */ + struct huffman lencode, distcode; /* length and distance codes */ + static const short order[19] = /* permutation of code length codes */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* construct lencode and distcode */ + lencode.count = lencnt; + lencode.symbol = lensym; + distcode.count = distcnt; + distcode.symbol = distsym; + + /* get number of lengths in each table, check lengths */ + nlen = bits(s, 5) + 257; + ndist = bits(s, 5) + 1; + ncode = bits(s, 4) + 4; + if (nlen > MAXLCODES || ndist > MAXDCODES) + return -3; /* bad counts */ + + /* read code length code lengths (really), missing lengths are zero */ + for (index = 0; index < ncode; index++) + lengths[order[index]] = bits(s, 3); + for (; index < 19; index++) + lengths[order[index]] = 0; + + /* build huffman table for code lengths codes (use lencode temporarily) */ + err = construct(&lencode, lengths, 19); + if (err != 0) /* require complete code set here */ + return -4; + + /* read length/literal and distance code length tables */ + index = 0; + while (index < nlen + ndist) { + int symbol; /* decoded value */ + int len; /* last length to repeat */ + + symbol = decode(s, &lencode); + if (symbol < 0) + return symbol; /* invalid symbol */ + if (symbol < 16) /* length in 0..15 */ + lengths[index++] = symbol; + else { /* repeat instruction */ + len = 0; /* assume repeating zeros */ + if (symbol == 16) { /* repeat last length 3..6 times */ + if (index == 0) + return -5; /* no last length! */ + len = lengths[index - 1]; /* last length */ + symbol = 3 + bits(s, 2); + } + else if (symbol == 17) /* repeat zero 3..10 times */ + symbol = 3 + bits(s, 3); + else /* == 18, repeat zero 11..138 times */ + symbol = 11 + bits(s, 7); + if (index + symbol > nlen + ndist) + return -6; /* too many lengths! */ + while (symbol--) /* repeat last or zero symbol times */ + lengths[index++] = len; + } + } + + /* check for end-of-block code -- there better be one! */ + if (lengths[256] == 0) + return -9; + + /* build huffman table for literal/length codes */ + err = construct(&lencode, lengths, nlen); + if (err && (err < 0 || nlen != lencode.count[0] + lencode.count[1])) + return -7; /* incomplete code ok only for single length 1 code */ + + /* build huffman table for distance codes */ + err = construct(&distcode, lengths + nlen, ndist); + if (err && (err < 0 || ndist != distcode.count[0] + distcode.count[1])) + return -8; /* incomplete code ok only for single length 1 code */ + + /* decode data until end-of-block code */ + return codes(s, &lencode, &distcode); +} + +/* + * Inflate source to dest. On return, destlen and sourcelen are updated to the + * size of the uncompressed data and the size of the deflate data respectively. + * On success, the return value of puff() is zero. If there is an error in the + * source data, i.e. it is not in the deflate format, then a negative value is + * returned. If there is not enough input available or there is not enough + * output space, then a positive error is returned. In that case, destlen and + * sourcelen are not updated to facilitate retrying from the beginning with the + * provision of more input data or more output space. In the case of invalid + * inflate data (a negative error), the dest and source pointers are updated to + * facilitate the debugging of deflators. + * + * puff() also has a mode to determine the size of the uncompressed output with + * no output written. For this dest must be (unsigned char *)0. In this case, + * the input value of *destlen is ignored, and on return *destlen is set to the + * size of the uncompressed output. + * + * The return codes are: + * + * 2: available inflate data did not terminate + * 1: output space exhausted before completing inflate + * 0: successful inflate + * -1: invalid block type (type == 3) + * -2: stored block length did not match one's complement + * -3: dynamic block code description: too many length or distance codes + * -4: dynamic block code description: code lengths codes incomplete + * -5: dynamic block code description: repeat lengths with no first length + * -6: dynamic block code description: repeat more than specified lengths + * -7: dynamic block code description: invalid literal/length code lengths + * -8: dynamic block code description: invalid distance code lengths + * -9: dynamic block code description: missing end-of-block code + * -10: invalid literal/length or distance code in fixed or dynamic block + * -11: distance is too far back in fixed or dynamic block + * + * Format notes: + * + * - Three bits are read for each block to determine the kind of block and + * whether or not it is the last block. Then the block is decoded and the + * process repeated if it was not the last block. + * + * - The leftover bits in the last byte of the deflate data after the last + * block (if it was a fixed or dynamic block) are undefined and have no + * expected values to check. + */ +int puff(unsigned char *dest, /* pointer to destination pointer */ + unsigned long *destlen, /* amount of output space */ + const unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen) /* amount of input available */ +{ + struct state s; /* input/output state */ + int last, type; /* block information */ + int err; /* return value */ + + /* initialize output state */ + s.out = dest; + s.outlen = *destlen; /* ignored if dest is NIL */ + s.outcnt = 0; + + /* initialize input state */ + s.in = source; + s.inlen = *sourcelen; + s.incnt = 0; + s.bitbuf = 0; + s.bitcnt = 0; + + /* return if bits() or decode() tries to read past available input */ + if (setjmp(s.env) != 0) /* if came back here via longjmp() */ + err = 2; /* then skip do-loop, return error */ + else { + /* process blocks until last block or error */ + do { + last = bits(&s, 1); /* one if last block */ + type = bits(&s, 2); /* block type 0..3 */ + err = type == 0 ? + stored(&s) : + (type == 1 ? + fixed(&s) : + (type == 2 ? + dynamic(&s) : + -1)); /* type == 3, invalid */ + if (err != 0) + break; /* return with error */ + } while (!last); + } + + /* update the lengths and return */ + if (err <= 0) { + *destlen = s.outcnt; + *sourcelen = s.incnt; + } + return err; +} diff --git a/test/zlib/zlib-1.2.8/contrib/puff/puff.h b/test/zlib/zlib-1.2.8/contrib/puff/puff.h new file mode 100644 index 000000000..e23a24543 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/puff/puff.h @@ -0,0 +1,35 @@ +/* puff.h + Copyright (C) 2002-2013 Mark Adler, all rights reserved + version 2.3, 21 Jan 2013 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + + +/* + * See puff.c for purpose and usage. + */ +#ifndef NIL +# define NIL ((unsigned char *)0) /* for no output option */ +#endif + +int puff(unsigned char *dest, /* pointer to destination pointer */ + unsigned long *destlen, /* amount of output space */ + const unsigned char *source, /* pointer to source data pointer */ + unsigned long *sourcelen); /* amount of input available */ diff --git a/test/zlib/zlib-1.2.8/contrib/puff/pufftest.c b/test/zlib/zlib-1.2.8/contrib/puff/pufftest.c new file mode 100644 index 000000000..776481488 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/puff/pufftest.c @@ -0,0 +1,165 @@ +/* + * pufftest.c + * Copyright (C) 2002-2013 Mark Adler + * For conditions of distribution and use, see copyright notice in puff.h + * version 2.3, 21 Jan 2013 + */ + +/* Example of how to use puff(). + + Usage: puff [-w] [-f] [-nnn] file + ... | puff [-w] [-f] [-nnn] + + where file is the input file with deflate data, nnn is the number of bytes + of input to skip before inflating (e.g. to skip a zlib or gzip header), and + -w is used to write the decompressed data to stdout. -f is for coverage + testing, and causes pufftest to fail with not enough output space (-f does + a write like -w, so -w is not required). */ + +#include +#include +#include "puff.h" + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#define local static + +/* Return size times approximately the cube root of 2, keeping the result as 1, + 3, or 5 times a power of 2 -- the result is always > size, until the result + is the maximum value of an unsigned long, where it remains. This is useful + to keep reallocations less than ~33% over the actual data. */ +local size_t bythirds(size_t size) +{ + int n; + size_t m; + + m = size; + for (n = 0; m; n++) + m >>= 1; + if (n < 3) + return size + 1; + n -= 3; + m = size >> n; + m += m == 6 ? 2 : 1; + m <<= n; + return m > size ? m : (size_t)(-1); +} + +/* Read the input file *name, or stdin if name is NULL, into allocated memory. + Reallocate to larger buffers until the entire file is read in. Return a + pointer to the allocated data, or NULL if there was a memory allocation + failure. *len is the number of bytes of data read from the input file (even + if load() returns NULL). If the input file was empty or could not be opened + or read, *len is zero. */ +local void *load(const char *name, size_t *len) +{ + size_t size; + void *buf, *swap; + FILE *in; + + *len = 0; + buf = malloc(size = 4096); + if (buf == NULL) + return NULL; + in = name == NULL ? stdin : fopen(name, "rb"); + if (in != NULL) { + for (;;) { + *len += fread((char *)buf + *len, 1, size - *len, in); + if (*len < size) break; + size = bythirds(size); + if (size == *len || (swap = realloc(buf, size)) == NULL) { + free(buf); + buf = NULL; + break; + } + buf = swap; + } + fclose(in); + } + return buf; +} + +int main(int argc, char **argv) +{ + int ret, put = 0, fail = 0; + unsigned skip = 0; + char *arg, *name = NULL; + unsigned char *source = NULL, *dest; + size_t len = 0; + unsigned long sourcelen, destlen; + + /* process arguments */ + while (arg = *++argv, --argc) + if (arg[0] == '-') { + if (arg[1] == 'w' && arg[2] == 0) + put = 1; + else if (arg[1] == 'f' && arg[2] == 0) + fail = 1, put = 1; + else if (arg[1] >= '0' && arg[1] <= '9') + skip = (unsigned)atoi(arg + 1); + else { + fprintf(stderr, "invalid option %s\n", arg); + return 3; + } + } + else if (name != NULL) { + fprintf(stderr, "only one file name allowed\n"); + return 3; + } + else + name = arg; + source = load(name, &len); + if (source == NULL) { + fprintf(stderr, "memory allocation failure\n"); + return 4; + } + if (len == 0) { + fprintf(stderr, "could not read %s, or it was empty\n", + name == NULL ? "" : name); + free(source); + return 3; + } + if (skip >= len) { + fprintf(stderr, "skip request of %d leaves no input\n", skip); + free(source); + return 3; + } + + /* test inflate data with offset skip */ + len -= skip; + sourcelen = (unsigned long)len; + ret = puff(NIL, &destlen, source + skip, &sourcelen); + if (ret) + fprintf(stderr, "puff() failed with return code %d\n", ret); + else { + fprintf(stderr, "puff() succeeded uncompressing %lu bytes\n", destlen); + if (sourcelen < len) fprintf(stderr, "%lu compressed bytes unused\n", + len - sourcelen); + } + + /* if requested, inflate again and write decompressd data to stdout */ + if (put && ret == 0) { + if (fail) + destlen >>= 1; + dest = malloc(destlen); + if (dest == NULL) { + fprintf(stderr, "memory allocation failure\n"); + free(source); + return 4; + } + puff(dest, &destlen, source + skip, &sourcelen); + SET_BINARY_MODE(stdout); + fwrite(dest, 1, destlen, stdout); + free(dest); + } + + /* clean up */ + free(source); + return ret; +} diff --git a/test/zlib/zlib-1.2.8/contrib/puff/zeros.raw b/test/zlib/zlib-1.2.8/contrib/puff/zeros.raw new file mode 100644 index 0000000000000000000000000000000000000000..0a90e76b300205a44a0ecbf613e64aaaef2e51e7 GIT binary patch literal 2517 zcmYdFkYHV$AkxzmXu#!mP=i#?5{3o^3jqcYc(h*%Opg+yAut*OqaiT#LSPd+y9&tF zP5<`ixi4UXdB8xJfs^6ee;AkH?VUytyFsD;HLIJ(gg5bUnNh}Q2#kinXb22!2pr%5 E0JRq+;s5{u literal 0 HcmV?d00001 diff --git a/test/zlib/zlib-1.2.8/contrib/testzlib/testzlib.c b/test/zlib/zlib-1.2.8/contrib/testzlib/testzlib.c new file mode 100644 index 000000000..8626c92ad --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/testzlib/testzlib.c @@ -0,0 +1,275 @@ +#include +#include +#include + +#include "zlib.h" + + +void MyDoMinus64(LARGE_INTEGER *R,LARGE_INTEGER A,LARGE_INTEGER B) +{ + R->HighPart = A.HighPart - B.HighPart; + if (A.LowPart >= B.LowPart) + R->LowPart = A.LowPart - B.LowPart; + else + { + R->LowPart = A.LowPart - B.LowPart; + R->HighPart --; + } +} + +#ifdef _M_X64 +// see http://msdn2.microsoft.com/library/twchhe95(en-us,vs.80).aspx for __rdtsc +unsigned __int64 __rdtsc(void); +void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64) +{ + // printf("rdtsc = %I64x\n",__rdtsc()); + pbeginTime64->QuadPart=__rdtsc(); +} + +LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf) +{ + LARGE_INTEGER LIres; + unsigned _int64 res=__rdtsc()-((unsigned _int64)(beginTime64.QuadPart)); + LIres.QuadPart=res; + // printf("rdtsc = %I64x\n",__rdtsc()); + return LIres; +} +#else +#ifdef _M_IX86 +void myGetRDTSC32(LARGE_INTEGER * pbeginTime64) +{ + DWORD dwEdx,dwEax; + _asm + { + rdtsc + mov dwEax,eax + mov dwEdx,edx + } + pbeginTime64->LowPart=dwEax; + pbeginTime64->HighPart=dwEdx; +} + +void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64) +{ + myGetRDTSC32(pbeginTime64); +} + +LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf) +{ + LARGE_INTEGER LIres,endTime64; + myGetRDTSC32(&endTime64); + + LIres.LowPart=LIres.HighPart=0; + MyDoMinus64(&LIres,endTime64,beginTime64); + return LIres; +} +#else +void myGetRDTSC32(LARGE_INTEGER * pbeginTime64) +{ +} + +void BeginCountRdtsc(LARGE_INTEGER * pbeginTime64) +{ +} + +LARGE_INTEGER GetResRdtsc(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf) +{ + LARGE_INTEGER lr; + lr.QuadPart=0; + return lr; +} +#endif +#endif + +void BeginCountPerfCounter(LARGE_INTEGER * pbeginTime64,BOOL fComputeTimeQueryPerf) +{ + if ((!fComputeTimeQueryPerf) || (!QueryPerformanceCounter(pbeginTime64))) + { + pbeginTime64->LowPart = GetTickCount(); + pbeginTime64->HighPart = 0; + } +} + +DWORD GetMsecSincePerfCounter(LARGE_INTEGER beginTime64,BOOL fComputeTimeQueryPerf) +{ + LARGE_INTEGER endTime64,ticksPerSecond,ticks; + DWORDLONG ticksShifted,tickSecShifted; + DWORD dwLog=16+0; + DWORD dwRet; + if ((!fComputeTimeQueryPerf) || (!QueryPerformanceCounter(&endTime64))) + dwRet = (GetTickCount() - beginTime64.LowPart)*1; + else + { + MyDoMinus64(&ticks,endTime64,beginTime64); + QueryPerformanceFrequency(&ticksPerSecond); + + + { + ticksShifted = Int64ShrlMod32(*(DWORDLONG*)&ticks,dwLog); + tickSecShifted = Int64ShrlMod32(*(DWORDLONG*)&ticksPerSecond,dwLog); + + } + + dwRet = (DWORD)((((DWORD)ticksShifted)*1000)/(DWORD)(tickSecShifted)); + dwRet *=1; + } + return dwRet; +} + +int ReadFileMemory(const char* filename,long* plFileSize,unsigned char** pFilePtr) +{ + FILE* stream; + unsigned char* ptr; + int retVal=1; + stream=fopen(filename, "rb"); + if (stream==NULL) + return 0; + + fseek(stream,0,SEEK_END); + + *plFileSize=ftell(stream); + fseek(stream,0,SEEK_SET); + ptr=malloc((*plFileSize)+1); + if (ptr==NULL) + retVal=0; + else + { + if (fread(ptr, 1, *plFileSize,stream) != (*plFileSize)) + retVal=0; + } + fclose(stream); + *pFilePtr=ptr; + return retVal; +} + +int main(int argc, char *argv[]) +{ + int BlockSizeCompress=0x8000; + int BlockSizeUncompress=0x8000; + int cprLevel=Z_DEFAULT_COMPRESSION ; + long lFileSize; + unsigned char* FilePtr; + long lBufferSizeCpr; + long lBufferSizeUncpr; + long lCompressedSize=0; + unsigned char* CprPtr; + unsigned char* UncprPtr; + long lSizeCpr,lSizeUncpr; + DWORD dwGetTick,dwMsecQP; + LARGE_INTEGER li_qp,li_rdtsc,dwResRdtsc; + + if (argc<=1) + { + printf("run TestZlib [BlockSizeCompress] [BlockSizeUncompress] [compres. level]\n"); + return 0; + } + + if (ReadFileMemory(argv[1],&lFileSize,&FilePtr)==0) + { + printf("error reading %s\n",argv[1]); + return 1; + } + else printf("file %s read, %u bytes\n",argv[1],lFileSize); + + if (argc>=3) + BlockSizeCompress=atol(argv[2]); + + if (argc>=4) + BlockSizeUncompress=atol(argv[3]); + + if (argc>=5) + cprLevel=(int)atol(argv[4]); + + lBufferSizeCpr = lFileSize + (lFileSize/0x10) + 0x200; + lBufferSizeUncpr = lBufferSizeCpr; + + CprPtr=(unsigned char*)malloc(lBufferSizeCpr + BlockSizeCompress); + + BeginCountPerfCounter(&li_qp,TRUE); + dwGetTick=GetTickCount(); + BeginCountRdtsc(&li_rdtsc); + { + z_stream zcpr; + int ret=Z_OK; + long lOrigToDo = lFileSize; + long lOrigDone = 0; + int step=0; + memset(&zcpr,0,sizeof(z_stream)); + deflateInit(&zcpr,cprLevel); + + zcpr.next_in = FilePtr; + zcpr.next_out = CprPtr; + + + do + { + long all_read_before = zcpr.total_in; + zcpr.avail_in = min(lOrigToDo,BlockSizeCompress); + zcpr.avail_out = BlockSizeCompress; + ret=deflate(&zcpr,(zcpr.avail_in==lOrigToDo) ? Z_FINISH : Z_SYNC_FLUSH); + lOrigDone += (zcpr.total_in-all_read_before); + lOrigToDo -= (zcpr.total_in-all_read_before); + step++; + } while (ret==Z_OK); + + lSizeCpr=zcpr.total_out; + deflateEnd(&zcpr); + dwGetTick=GetTickCount()-dwGetTick; + dwMsecQP=GetMsecSincePerfCounter(li_qp,TRUE); + dwResRdtsc=GetResRdtsc(li_rdtsc,TRUE); + printf("total compress size = %u, in %u step\n",lSizeCpr,step); + printf("time = %u msec = %f sec\n",dwGetTick,dwGetTick/(double)1000.); + printf("defcpr time QP = %u msec = %f sec\n",dwMsecQP,dwMsecQP/(double)1000.); + printf("defcpr result rdtsc = %I64x\n\n",dwResRdtsc.QuadPart); + } + + CprPtr=(unsigned char*)realloc(CprPtr,lSizeCpr); + UncprPtr=(unsigned char*)malloc(lBufferSizeUncpr + BlockSizeUncompress); + + BeginCountPerfCounter(&li_qp,TRUE); + dwGetTick=GetTickCount(); + BeginCountRdtsc(&li_rdtsc); + { + z_stream zcpr; + int ret=Z_OK; + long lOrigToDo = lSizeCpr; + long lOrigDone = 0; + int step=0; + memset(&zcpr,0,sizeof(z_stream)); + inflateInit(&zcpr); + + zcpr.next_in = CprPtr; + zcpr.next_out = UncprPtr; + + + do + { + long all_read_before = zcpr.total_in; + zcpr.avail_in = min(lOrigToDo,BlockSizeUncompress); + zcpr.avail_out = BlockSizeUncompress; + ret=inflate(&zcpr,Z_SYNC_FLUSH); + lOrigDone += (zcpr.total_in-all_read_before); + lOrigToDo -= (zcpr.total_in-all_read_before); + step++; + } while (ret==Z_OK); + + lSizeUncpr=zcpr.total_out; + inflateEnd(&zcpr); + dwGetTick=GetTickCount()-dwGetTick; + dwMsecQP=GetMsecSincePerfCounter(li_qp,TRUE); + dwResRdtsc=GetResRdtsc(li_rdtsc,TRUE); + printf("total uncompress size = %u, in %u step\n",lSizeUncpr,step); + printf("time = %u msec = %f sec\n",dwGetTick,dwGetTick/(double)1000.); + printf("uncpr time QP = %u msec = %f sec\n",dwMsecQP,dwMsecQP/(double)1000.); + printf("uncpr result rdtsc = %I64x\n\n",dwResRdtsc.QuadPart); + } + + if (lSizeUncpr==lFileSize) + { + if (memcmp(FilePtr,UncprPtr,lFileSize)==0) + printf("compare ok\n"); + + } + + return 0; +} diff --git a/test/zlib/zlib-1.2.8/contrib/testzlib/testzlib.txt b/test/zlib/zlib-1.2.8/contrib/testzlib/testzlib.txt new file mode 100644 index 000000000..e508bb22f --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/testzlib/testzlib.txt @@ -0,0 +1,10 @@ +To build testzLib with Visual Studio 2005: + +copy to a directory file from : +- root of zLib tree +- contrib/testzlib +- contrib/masmx86 +- contrib/masmx64 +- contrib/vstudio/vc7 + +and open testzlib8.sln \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/untgz/Makefile b/test/zlib/zlib-1.2.8/contrib/untgz/Makefile new file mode 100644 index 000000000..b54266fba --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/untgz/Makefile @@ -0,0 +1,14 @@ +CC=cc +CFLAGS=-g + +untgz: untgz.o ../../libz.a + $(CC) $(CFLAGS) -o untgz untgz.o -L../.. -lz + +untgz.o: untgz.c ../../zlib.h + $(CC) $(CFLAGS) -c -I../.. untgz.c + +../../libz.a: + cd ../..; ./configure; make + +clean: + rm -f untgz untgz.o *~ diff --git a/test/zlib/zlib-1.2.8/contrib/untgz/Makefile.msc b/test/zlib/zlib-1.2.8/contrib/untgz/Makefile.msc new file mode 100644 index 000000000..77b860221 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/untgz/Makefile.msc @@ -0,0 +1,17 @@ +CC=cl +CFLAGS=-MD + +untgz.exe: untgz.obj ..\..\zlib.lib + $(CC) $(CFLAGS) untgz.obj ..\..\zlib.lib + +untgz.obj: untgz.c ..\..\zlib.h + $(CC) $(CFLAGS) -c -I..\.. untgz.c + +..\..\zlib.lib: + cd ..\.. + $(MAKE) -f win32\makefile.msc + cd contrib\untgz + +clean: + -del untgz.obj + -del untgz.exe diff --git a/test/zlib/zlib-1.2.8/contrib/untgz/untgz.c b/test/zlib/zlib-1.2.8/contrib/untgz/untgz.c new file mode 100644 index 000000000..2c391e598 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/untgz/untgz.c @@ -0,0 +1,674 @@ +/* + * untgz.c -- Display contents and extract files from a gzip'd TAR file + * + * written by Pedro A. Aranda Gutierrez + * adaptation to Unix by Jean-loup Gailly + * various fixes by Cosmin Truta + */ + +#include +#include +#include +#include +#include + +#include "zlib.h" + +#ifdef unix +# include +#else +# include +# include +#endif + +#ifdef WIN32 +#include +# ifndef F_OK +# define F_OK 0 +# endif +# define mkdir(dirname,mode) _mkdir(dirname) +# ifdef _MSC_VER +# define access(path,mode) _access(path,mode) +# define chmod(path,mode) _chmod(path,mode) +# define strdup(str) _strdup(str) +# endif +#else +# include +#endif + + +/* values used in typeflag field */ + +#define REGTYPE '0' /* regular file */ +#define AREGTYPE '\0' /* regular file */ +#define LNKTYPE '1' /* link */ +#define SYMTYPE '2' /* reserved */ +#define CHRTYPE '3' /* character special */ +#define BLKTYPE '4' /* block special */ +#define DIRTYPE '5' /* directory */ +#define FIFOTYPE '6' /* FIFO special */ +#define CONTTYPE '7' /* reserved */ + +/* GNU tar extensions */ + +#define GNUTYPE_DUMPDIR 'D' /* file names from dumped directory */ +#define GNUTYPE_LONGLINK 'K' /* long link name */ +#define GNUTYPE_LONGNAME 'L' /* long file name */ +#define GNUTYPE_MULTIVOL 'M' /* continuation of file from another volume */ +#define GNUTYPE_NAMES 'N' /* file name that does not fit into main hdr */ +#define GNUTYPE_SPARSE 'S' /* sparse file */ +#define GNUTYPE_VOLHDR 'V' /* tape/volume header */ + + +/* tar header */ + +#define BLOCKSIZE 512 +#define SHORTNAMESIZE 100 + +struct tar_header +{ /* byte offset */ + char name[100]; /* 0 */ + char mode[8]; /* 100 */ + char uid[8]; /* 108 */ + char gid[8]; /* 116 */ + char size[12]; /* 124 */ + char mtime[12]; /* 136 */ + char chksum[8]; /* 148 */ + char typeflag; /* 156 */ + char linkname[100]; /* 157 */ + char magic[6]; /* 257 */ + char version[2]; /* 263 */ + char uname[32]; /* 265 */ + char gname[32]; /* 297 */ + char devmajor[8]; /* 329 */ + char devminor[8]; /* 337 */ + char prefix[155]; /* 345 */ + /* 500 */ +}; + +union tar_buffer +{ + char buffer[BLOCKSIZE]; + struct tar_header header; +}; + +struct attr_item +{ + struct attr_item *next; + char *fname; + int mode; + time_t time; +}; + +enum { TGZ_EXTRACT, TGZ_LIST, TGZ_INVALID }; + +char *TGZfname OF((const char *)); +void TGZnotfound OF((const char *)); + +int getoct OF((char *, int)); +char *strtime OF((time_t *)); +int setfiletime OF((char *, time_t)); +void push_attr OF((struct attr_item **, char *, int, time_t)); +void restore_attr OF((struct attr_item **)); + +int ExprMatch OF((char *, char *)); + +int makedir OF((char *)); +int matchname OF((int, int, char **, char *)); + +void error OF((const char *)); +int tar OF((gzFile, int, int, int, char **)); + +void help OF((int)); +int main OF((int, char **)); + +char *prog; + +const char *TGZsuffix[] = { "\0", ".tar", ".tar.gz", ".taz", ".tgz", NULL }; + +/* return the file name of the TGZ archive */ +/* or NULL if it does not exist */ + +char *TGZfname (const char *arcname) +{ + static char buffer[1024]; + int origlen,i; + + strcpy(buffer,arcname); + origlen = strlen(buffer); + + for (i=0; TGZsuffix[i]; i++) + { + strcpy(buffer+origlen,TGZsuffix[i]); + if (access(buffer,F_OK) == 0) + return buffer; + } + return NULL; +} + + +/* error message for the filename */ + +void TGZnotfound (const char *arcname) +{ + int i; + + fprintf(stderr,"%s: Couldn't find ",prog); + for (i=0;TGZsuffix[i];i++) + fprintf(stderr,(TGZsuffix[i+1]) ? "%s%s, " : "or %s%s\n", + arcname, + TGZsuffix[i]); + exit(1); +} + + +/* convert octal digits to int */ +/* on error return -1 */ + +int getoct (char *p,int width) +{ + int result = 0; + char c; + + while (width--) + { + c = *p++; + if (c == 0) + break; + if (c == ' ') + continue; + if (c < '0' || c > '7') + return -1; + result = result * 8 + (c - '0'); + } + return result; +} + + +/* convert time_t to string */ +/* use the "YYYY/MM/DD hh:mm:ss" format */ + +char *strtime (time_t *t) +{ + struct tm *local; + static char result[32]; + + local = localtime(t); + sprintf(result,"%4d/%02d/%02d %02d:%02d:%02d", + local->tm_year+1900, local->tm_mon+1, local->tm_mday, + local->tm_hour, local->tm_min, local->tm_sec); + return result; +} + + +/* set file time */ + +int setfiletime (char *fname,time_t ftime) +{ +#ifdef WIN32 + static int isWinNT = -1; + SYSTEMTIME st; + FILETIME locft, modft; + struct tm *loctm; + HANDLE hFile; + int result; + + loctm = localtime(&ftime); + if (loctm == NULL) + return -1; + + st.wYear = (WORD)loctm->tm_year + 1900; + st.wMonth = (WORD)loctm->tm_mon + 1; + st.wDayOfWeek = (WORD)loctm->tm_wday; + st.wDay = (WORD)loctm->tm_mday; + st.wHour = (WORD)loctm->tm_hour; + st.wMinute = (WORD)loctm->tm_min; + st.wSecond = (WORD)loctm->tm_sec; + st.wMilliseconds = 0; + if (!SystemTimeToFileTime(&st, &locft) || + !LocalFileTimeToFileTime(&locft, &modft)) + return -1; + + if (isWinNT < 0) + isWinNT = (GetVersion() < 0x80000000) ? 1 : 0; + hFile = CreateFile(fname, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, + (isWinNT ? FILE_FLAG_BACKUP_SEMANTICS : 0), + NULL); + if (hFile == INVALID_HANDLE_VALUE) + return -1; + result = SetFileTime(hFile, NULL, NULL, &modft) ? 0 : -1; + CloseHandle(hFile); + return result; +#else + struct utimbuf settime; + + settime.actime = settime.modtime = ftime; + return utime(fname,&settime); +#endif +} + + +/* push file attributes */ + +void push_attr(struct attr_item **list,char *fname,int mode,time_t time) +{ + struct attr_item *item; + + item = (struct attr_item *)malloc(sizeof(struct attr_item)); + if (item == NULL) + error("Out of memory"); + item->fname = strdup(fname); + item->mode = mode; + item->time = time; + item->next = *list; + *list = item; +} + + +/* restore file attributes */ + +void restore_attr(struct attr_item **list) +{ + struct attr_item *item, *prev; + + for (item = *list; item != NULL; ) + { + setfiletime(item->fname,item->time); + chmod(item->fname,item->mode); + prev = item; + item = item->next; + free(prev); + } + *list = NULL; +} + + +/* match regular expression */ + +#define ISSPECIAL(c) (((c) == '*') || ((c) == '/')) + +int ExprMatch (char *string,char *expr) +{ + while (1) + { + if (ISSPECIAL(*expr)) + { + if (*expr == '/') + { + if (*string != '\\' && *string != '/') + return 0; + string ++; expr++; + } + else if (*expr == '*') + { + if (*expr ++ == 0) + return 1; + while (*++string != *expr) + if (*string == 0) + return 0; + } + } + else + { + if (*string != *expr) + return 0; + if (*expr++ == 0) + return 1; + string++; + } + } +} + + +/* recursive mkdir */ +/* abort on ENOENT; ignore other errors like "directory already exists" */ +/* return 1 if OK */ +/* 0 on error */ + +int makedir (char *newdir) +{ + char *buffer = strdup(newdir); + char *p; + int len = strlen(buffer); + + if (len <= 0) { + free(buffer); + return 0; + } + if (buffer[len-1] == '/') { + buffer[len-1] = '\0'; + } + if (mkdir(buffer, 0755) == 0) + { + free(buffer); + return 1; + } + + p = buffer+1; + while (1) + { + char hold; + + while(*p && *p != '\\' && *p != '/') + p++; + hold = *p; + *p = 0; + if ((mkdir(buffer, 0755) == -1) && (errno == ENOENT)) + { + fprintf(stderr,"%s: Couldn't create directory %s\n",prog,buffer); + free(buffer); + return 0; + } + if (hold == 0) + break; + *p++ = hold; + } + free(buffer); + return 1; +} + + +int matchname (int arg,int argc,char **argv,char *fname) +{ + if (arg == argc) /* no arguments given (untgz tgzarchive) */ + return 1; + + while (arg < argc) + if (ExprMatch(fname,argv[arg++])) + return 1; + + return 0; /* ignore this for the moment being */ +} + + +/* tar file list or extract */ + +int tar (gzFile in,int action,int arg,int argc,char **argv) +{ + union tar_buffer buffer; + int len; + int err; + int getheader = 1; + int remaining = 0; + FILE *outfile = NULL; + char fname[BLOCKSIZE]; + int tarmode; + time_t tartime; + struct attr_item *attributes = NULL; + + if (action == TGZ_LIST) + printf(" date time size file\n" + " ---------- -------- --------- -------------------------------------\n"); + while (1) + { + len = gzread(in, &buffer, BLOCKSIZE); + if (len < 0) + error(gzerror(in, &err)); + /* + * Always expect complete blocks to process + * the tar information. + */ + if (len != BLOCKSIZE) + { + action = TGZ_INVALID; /* force error exit */ + remaining = 0; /* force I/O cleanup */ + } + + /* + * If we have to get a tar header + */ + if (getheader >= 1) + { + /* + * if we met the end of the tar + * or the end-of-tar block, + * we are done + */ + if (len == 0 || buffer.header.name[0] == 0) + break; + + tarmode = getoct(buffer.header.mode,8); + tartime = (time_t)getoct(buffer.header.mtime,12); + if (tarmode == -1 || tartime == (time_t)-1) + { + buffer.header.name[0] = 0; + action = TGZ_INVALID; + } + + if (getheader == 1) + { + strncpy(fname,buffer.header.name,SHORTNAMESIZE); + if (fname[SHORTNAMESIZE-1] != 0) + fname[SHORTNAMESIZE] = 0; + } + else + { + /* + * The file name is longer than SHORTNAMESIZE + */ + if (strncmp(fname,buffer.header.name,SHORTNAMESIZE-1) != 0) + error("bad long name"); + getheader = 1; + } + + /* + * Act according to the type flag + */ + switch (buffer.header.typeflag) + { + case DIRTYPE: + if (action == TGZ_LIST) + printf(" %s %s\n",strtime(&tartime),fname); + if (action == TGZ_EXTRACT) + { + makedir(fname); + push_attr(&attributes,fname,tarmode,tartime); + } + break; + case REGTYPE: + case AREGTYPE: + remaining = getoct(buffer.header.size,12); + if (remaining == -1) + { + action = TGZ_INVALID; + break; + } + if (action == TGZ_LIST) + printf(" %s %9d %s\n",strtime(&tartime),remaining,fname); + else if (action == TGZ_EXTRACT) + { + if (matchname(arg,argc,argv,fname)) + { + outfile = fopen(fname,"wb"); + if (outfile == NULL) { + /* try creating directory */ + char *p = strrchr(fname, '/'); + if (p != NULL) { + *p = '\0'; + makedir(fname); + *p = '/'; + outfile = fopen(fname,"wb"); + } + } + if (outfile != NULL) + printf("Extracting %s\n",fname); + else + fprintf(stderr, "%s: Couldn't create %s",prog,fname); + } + else + outfile = NULL; + } + getheader = 0; + break; + case GNUTYPE_LONGLINK: + case GNUTYPE_LONGNAME: + remaining = getoct(buffer.header.size,12); + if (remaining < 0 || remaining >= BLOCKSIZE) + { + action = TGZ_INVALID; + break; + } + len = gzread(in, fname, BLOCKSIZE); + if (len < 0) + error(gzerror(in, &err)); + if (fname[BLOCKSIZE-1] != 0 || (int)strlen(fname) > remaining) + { + action = TGZ_INVALID; + break; + } + getheader = 2; + break; + default: + if (action == TGZ_LIST) + printf(" %s <---> %s\n",strtime(&tartime),fname); + break; + } + } + else + { + unsigned int bytes = (remaining > BLOCKSIZE) ? BLOCKSIZE : remaining; + + if (outfile != NULL) + { + if (fwrite(&buffer,sizeof(char),bytes,outfile) != bytes) + { + fprintf(stderr, + "%s: Error writing %s -- skipping\n",prog,fname); + fclose(outfile); + outfile = NULL; + remove(fname); + } + } + remaining -= bytes; + } + + if (remaining == 0) + { + getheader = 1; + if (outfile != NULL) + { + fclose(outfile); + outfile = NULL; + if (action != TGZ_INVALID) + push_attr(&attributes,fname,tarmode,tartime); + } + } + + /* + * Abandon if errors are found + */ + if (action == TGZ_INVALID) + { + error("broken archive"); + break; + } + } + + /* + * Restore file modes and time stamps + */ + restore_attr(&attributes); + + if (gzclose(in) != Z_OK) + error("failed gzclose"); + + return 0; +} + + +/* ============================================================ */ + +void help(int exitval) +{ + printf("untgz version 0.2.1\n" + " using zlib version %s\n\n", + zlibVersion()); + printf("Usage: untgz file.tgz extract all files\n" + " untgz file.tgz fname ... extract selected files\n" + " untgz -l file.tgz list archive contents\n" + " untgz -h display this help\n"); + exit(exitval); +} + +void error(const char *msg) +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + + +/* ============================================================ */ + +#if defined(WIN32) && defined(__GNUC__) +int _CRT_glob = 0; /* disable argument globbing in MinGW */ +#endif + +int main(int argc,char **argv) +{ + int action = TGZ_EXTRACT; + int arg = 1; + char *TGZfile; + gzFile *f; + + prog = strrchr(argv[0],'\\'); + if (prog == NULL) + { + prog = strrchr(argv[0],'/'); + if (prog == NULL) + { + prog = strrchr(argv[0],':'); + if (prog == NULL) + prog = argv[0]; + else + prog++; + } + else + prog++; + } + else + prog++; + + if (argc == 1) + help(0); + + if (strcmp(argv[arg],"-l") == 0) + { + action = TGZ_LIST; + if (argc == ++arg) + help(0); + } + else if (strcmp(argv[arg],"-h") == 0) + { + help(0); + } + + if ((TGZfile = TGZfname(argv[arg])) == NULL) + TGZnotfound(argv[arg]); + + ++arg; + if ((action == TGZ_LIST) && (arg != argc)) + help(1); + +/* + * Process the TGZ file + */ + switch(action) + { + case TGZ_LIST: + case TGZ_EXTRACT: + f = gzopen(TGZfile,"rb"); + if (f == NULL) + { + fprintf(stderr,"%s: Couldn't gzopen %s\n",prog,TGZfile); + return 1; + } + exit(tar(f, action, arg, argc, argv)); + break; + + default: + error("Unknown option"); + exit(1); + } + + return 0; +} diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/readme.txt b/test/zlib/zlib-1.2.8/contrib/vstudio/readme.txt new file mode 100644 index 000000000..04b8baac8 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/readme.txt @@ -0,0 +1,65 @@ +Building instructions for the DLL versions of Zlib 1.2.8 +======================================================== + +This directory contains projects that build zlib and minizip using +Microsoft Visual C++ 9.0/10.0. + +You don't need to build these projects yourself. You can download the +binaries from: + http://www.winimage.com/zLibDll + +More information can be found at this site. + + + + + +Build instructions for Visual Studio 2008 (32 bits or 64 bits) +-------------------------------------------------------------- +- Uncompress current zlib, including all contrib/* files +- Compile assembly code (with Visual Studio Command Prompt) by running: + bld_ml64.bat (in contrib\masmx64) + bld_ml32.bat (in contrib\masmx86) +- Open contrib\vstudio\vc9\zlibvc.sln with Microsoft Visual C++ 2008 +- Or run: vcbuild /rebuild contrib\vstudio\vc9\zlibvc.sln "Release|Win32" + +Build instructions for Visual Studio 2010 (32 bits or 64 bits) +-------------------------------------------------------------- +- Uncompress current zlib, including all contrib/* files +- Open contrib\vstudio\vc10\zlibvc.sln with Microsoft Visual C++ 2010 + +Build instructions for Visual Studio 2012 (32 bits or 64 bits) +-------------------------------------------------------------- +- Uncompress current zlib, including all contrib/* files +- Open contrib\vstudio\vc11\zlibvc.sln with Microsoft Visual C++ 2012 + + +Important +--------- +- To use zlibwapi.dll in your application, you must define the + macro ZLIB_WINAPI when compiling your application's source files. + + +Additional notes +---------------- +- This DLL, named zlibwapi.dll, is compatible to the old zlib.dll built + by Gilles Vollant from the zlib 1.1.x sources, and distributed at + http://www.winimage.com/zLibDll + It uses the WINAPI calling convention for the exported functions, and + includes the minizip functionality. If your application needs that + particular build of zlib.dll, you can rename zlibwapi.dll to zlib.dll. + +- The new DLL was renamed because there exist several incompatible + versions of zlib.dll on the Internet. + +- There is also an official DLL build of zlib, named zlib1.dll. This one + is exporting the functions using the CDECL convention. See the file + win32\DLL_FAQ.txt found in this zlib distribution. + +- There used to be a ZLIB_DLL macro in zlib 1.1.x, but now this symbol + has a slightly different effect. To avoid compatibility problems, do + not define it here. + + +Gilles Vollant +info@winimage.com diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/miniunz.vcxproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/miniunz.vcxproj new file mode 100644 index 000000000..1b3624215 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/miniunz.vcxproj @@ -0,0 +1,310 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {C52F9E7B-498A-42BE-8DB4-85A15694382A} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\MiniUnzip$(Configuration)\ + x86\MiniUnzip$(Configuration)\Tmp\ + true + false + x86\MiniUnzip$(Configuration)\ + x86\MiniUnzip$(Configuration)\Tmp\ + false + false + x64\MiniUnzip$(Configuration)\ + x64\MiniUnzip$(Configuration)\Tmp\ + true + false + ia64\MiniUnzip$(Configuration)\ + ia64\MiniUnzip$(Configuration)\Tmp\ + true + false + x64\MiniUnzip$(Configuration)\ + x64\MiniUnzip$(Configuration)\Tmp\ + false + false + ia64\MiniUnzip$(Configuration)\ + ia64\MiniUnzip$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebug + false + + + $(IntDir) + Level3 + EditAndContinue + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/miniunz.vcxproj.filters b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/miniunz.vcxproj.filters new file mode 100644 index 000000000..0bd12210c --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/miniunz.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {048af943-022b-4db6-beeb-a54c34774ee2} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c1d600d2-888f-4aea-b73e-8b0dd9befa0c} + h;hpp;hxx;hm;inl;inc + + + {0844199a-966b-4f19-81db-1e0125e141b9} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/minizip.vcxproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/minizip.vcxproj new file mode 100644 index 000000000..ccd3651df --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/minizip.vcxproj @@ -0,0 +1,307 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\MiniZip$(Configuration)\ + x86\MiniZip$(Configuration)\Tmp\ + true + false + x86\MiniZip$(Configuration)\ + x86\MiniZip$(Configuration)\Tmp\ + false + x64\$(Configuration)\ + x64\$(Configuration)\ + true + false + ia64\$(Configuration)\ + ia64\$(Configuration)\ + true + false + x64\$(Configuration)\ + x64\$(Configuration)\ + false + ia64\$(Configuration)\ + ia64\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebug + false + + + $(IntDir) + Level3 + EditAndContinue + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/minizip.vcxproj.filters b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/minizip.vcxproj.filters new file mode 100644 index 000000000..7076d76ff --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/minizip.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {c0419b40-bf50-40da-b153-ff74215b79de} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {bb87b070-735b-478e-92ce-7383abb2f36c} + h;hpp;hxx;hm;inl;inc + + + {f46ab6a6-548f-43cb-ae96-681abb5bd5db} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlib.vcxproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlib.vcxproj new file mode 100644 index 000000000..476b8ea45 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlib.vcxproj @@ -0,0 +1,420 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B} + testzlib + Win32Proj + + + + Application + MultiByte + true + + + Application + MultiByte + true + + + Application + MultiByte + + + Application + MultiByte + true + + + Application + MultiByte + true + + + Application + MultiByte + + + Application + true + + + Application + true + + + Application + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + true + false + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + false + false + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + false + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + true + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + false + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebug + false + + + AssemblyAndSourceCode + $(IntDir) + Level3 + EditAndContinue + + + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + Console + true + true + false + + + MachineX86 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDebugDLL + false + $(IntDir) + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + + + + + Itanium + + + Disabled + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + AssemblyAndSourceCode + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + MachineIA64 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDLL + false + $(IntDir) + + + %(AdditionalDependencies) + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + MachineIA64 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDLL + false + $(IntDir) + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + MachineIA64 + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlib.vcxproj.filters b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlib.vcxproj.filters new file mode 100644 index 000000000..327649103 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlib.vcxproj.filters @@ -0,0 +1,58 @@ + + + + + {c1f6a2e3-5da5-4955-8653-310d3efe05a9} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {c2aaffdc-2c95-4d6f-8466-4bec5890af2c} + h;hpp;hxx;hm;inl;inc + + + {c274fe07-05f2-461c-964b-f6341e4e7eb5} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlibdll.vcxproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlibdll.vcxproj new file mode 100644 index 000000000..8e38876fa --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlibdll.vcxproj @@ -0,0 +1,310 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {C52F9E7B-498A-42BE-8DB4-85A15694366A} + Win32Proj + + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\TestZlibDll$(Configuration)\ + x86\TestZlibDll$(Configuration)\Tmp\ + true + false + x86\TestZlibDll$(Configuration)\ + x86\TestZlibDll$(Configuration)\Tmp\ + false + false + x64\TestZlibDll$(Configuration)\ + x64\TestZlibDll$(Configuration)\Tmp\ + true + false + ia64\TestZlibDll$(Configuration)\ + ia64\TestZlibDll$(Configuration)\Tmp\ + true + false + x64\TestZlibDll$(Configuration)\ + x64\TestZlibDll$(Configuration)\Tmp\ + false + false + ia64\TestZlibDll$(Configuration)\ + ia64\TestZlibDll$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebug + false + + + $(IntDir) + Level3 + EditAndContinue + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlibdll.vcxproj.filters b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlibdll.vcxproj.filters new file mode 100644 index 000000000..ab87f09f4 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/testzlibdll.vcxproj.filters @@ -0,0 +1,22 @@ + + + + + {fa61a89f-93fc-4c89-b29e-36224b7592f4} + cpp;c;cxx;def;odl;idl;hpj;bat;asm + + + {d4b85da0-2ba2-4934-b57f-e2584e3848ee} + h;hpp;hxx;hm;inl;inc + + + {e573e075-00bd-4a7d-bd67-a8cc9bfc5aca} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe + + + + + Source Files + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlib.rc b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlib.rc new file mode 100644 index 000000000..d42f191d3 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlib.rc @@ -0,0 +1,32 @@ +#include + +#define IDR_VERSION1 1 +IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE + FILEVERSION 1,2,8,0 + PRODUCTVERSION 1,2,8,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS 0 + FILEOS VOS_DOS_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + + BEGIN + VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0" + VALUE "FileVersion", "1.2.8\0" + VALUE "InternalName", "zlib\0" + VALUE "OriginalFilename", "zlibwapi.dll\0" + VALUE "ProductName", "ZLib.DLL\0" + VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" + VALUE "LegalCopyright", "(C) 1995-2013 Jean-loup Gailly & Mark Adler\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibstat.vcxproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibstat.vcxproj new file mode 100644 index 000000000..45389a352 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibstat.vcxproj @@ -0,0 +1,473 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8} + + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + + + MultiThreadedDebug + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibstat.lib + true + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + cd ..\..\masmx64 +bld_ml64.bat + + + + + Itanium + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibstat.lib + true + + + cd ..\..\masmx64 +bld_ml64.bat + + + + + Itanium + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibstat.vcxproj.filters b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibstat.vcxproj.filters new file mode 100644 index 000000000..0c8b2501c --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibstat.vcxproj.filters @@ -0,0 +1,77 @@ + + + + + {174213f6-7f66-4ae8-a3a8-a1e0a1e6ffdd} + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Source Files + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.def b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.def new file mode 100644 index 000000000..980fed3a4 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.def @@ -0,0 +1,143 @@ +LIBRARY +; zlib data compression and ZIP file I/O library + +VERSION 1.2.8 + +EXPORTS + adler32 @1 + compress @2 + crc32 @3 + deflate @4 + deflateCopy @5 + deflateEnd @6 + deflateInit2_ @7 + deflateInit_ @8 + deflateParams @9 + deflateReset @10 + deflateSetDictionary @11 + gzclose @12 + gzdopen @13 + gzerror @14 + gzflush @15 + gzopen @16 + gzread @17 + gzwrite @18 + inflate @19 + inflateEnd @20 + inflateInit2_ @21 + inflateInit_ @22 + inflateReset @23 + inflateSetDictionary @24 + inflateSync @25 + uncompress @26 + zlibVersion @27 + gzprintf @28 + gzputc @29 + gzgetc @30 + gzseek @31 + gzrewind @32 + gztell @33 + gzeof @34 + gzsetparams @35 + zError @36 + inflateSyncPoint @37 + get_crc_table @38 + compress2 @39 + gzputs @40 + gzgets @41 + inflateCopy @42 + inflateBackInit_ @43 + inflateBack @44 + inflateBackEnd @45 + compressBound @46 + deflateBound @47 + gzclearerr @48 + gzungetc @49 + zlibCompileFlags @50 + deflatePrime @51 + deflatePending @52 + + unzOpen @61 + unzClose @62 + unzGetGlobalInfo @63 + unzGetCurrentFileInfo @64 + unzGoToFirstFile @65 + unzGoToNextFile @66 + unzOpenCurrentFile @67 + unzReadCurrentFile @68 + unzOpenCurrentFile3 @69 + unztell @70 + unzeof @71 + unzCloseCurrentFile @72 + unzGetGlobalComment @73 + unzStringFileNameCompare @74 + unzLocateFile @75 + unzGetLocalExtrafield @76 + unzOpen2 @77 + unzOpenCurrentFile2 @78 + unzOpenCurrentFilePassword @79 + + zipOpen @80 + zipOpenNewFileInZip @81 + zipWriteInFileInZip @82 + zipCloseFileInZip @83 + zipClose @84 + zipOpenNewFileInZip2 @86 + zipCloseFileInZipRaw @87 + zipOpen2 @88 + zipOpenNewFileInZip3 @89 + + unzGetFilePos @100 + unzGoToFilePos @101 + + fill_win32_filefunc @110 + +; zlibwapi v1.2.4 added: + fill_win32_filefunc64 @111 + fill_win32_filefunc64A @112 + fill_win32_filefunc64W @113 + + unzOpen64 @120 + unzOpen2_64 @121 + unzGetGlobalInfo64 @122 + unzGetCurrentFileInfo64 @124 + unzGetCurrentFileZStreamPos64 @125 + unztell64 @126 + unzGetFilePos64 @127 + unzGoToFilePos64 @128 + + zipOpen64 @130 + zipOpen2_64 @131 + zipOpenNewFileInZip64 @132 + zipOpenNewFileInZip2_64 @133 + zipOpenNewFileInZip3_64 @134 + zipOpenNewFileInZip4_64 @135 + zipCloseFileInZipRaw64 @136 + +; zlib1 v1.2.4 added: + adler32_combine @140 + crc32_combine @142 + deflateSetHeader @144 + deflateTune @145 + gzbuffer @146 + gzclose_r @147 + gzclose_w @148 + gzdirect @149 + gzoffset @150 + inflateGetHeader @156 + inflateMark @157 + inflatePrime @158 + inflateReset2 @159 + inflateUndermine @160 + +; zlib1 v1.2.6 added: + gzgetc_ @161 + inflateResetKeep @163 + deflateResetKeep @164 + +; zlib1 v1.2.7 added: + gzopen_w @165 + +; zlib1 v1.2.8 added: + inflateGetDictionary @166 + gzvprintf @167 diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.sln b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.sln new file mode 100644 index 000000000..649f40c7e --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.sln @@ -0,0 +1,135 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "zlibvc.vcxproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "zlibstat.vcxproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlib", "testzlib.vcxproj", "{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlibdll", "testzlibdll.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694366A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "minizip.vcxproj", "{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniunz", "miniunz.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694382A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Itanium = Debug|Itanium + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Itanium = Release|Itanium + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseWithoutAsm|Itanium = ReleaseWithoutAsm|Itanium + ReleaseWithoutAsm|Win32 = ReleaseWithoutAsm|Win32 + ReleaseWithoutAsm|x64 = ReleaseWithoutAsm|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.ActiveCfg = Debug|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.Build.0 = Debug|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.Build.0 = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.ActiveCfg = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.Build.0 = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.ActiveCfg = Release|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.Build.0 = Release|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.ActiveCfg = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.Build.0 = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.ActiveCfg = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.Build.0 = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.ActiveCfg = Debug|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.Build.0 = Debug|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.Build.0 = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.ActiveCfg = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.Build.0 = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.ActiveCfg = Release|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.Build.0 = Release|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.ActiveCfg = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.Build.0 = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.ActiveCfg = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.Build.0 = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.Build.0 = Debug|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.Build.0 = Release|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.ActiveCfg = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.Build.0 = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.Build.0 = Debug|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.Build.0 = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.ActiveCfg = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.Build.0 = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.vcxproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.vcxproj new file mode 100644 index 000000000..7d7c49a6d --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.vcxproj @@ -0,0 +1,657 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {8FD826F8-3739-44E6-8CC8-997122E53B8D} + + + + DynamicLibrary + false + true + + + DynamicLibrary + false + true + + + DynamicLibrary + false + + + DynamicLibrary + false + true + + + DynamicLibrary + false + true + + + DynamicLibrary + false + + + DynamicLibrary + false + true + + + DynamicLibrary + false + true + + + DynamicLibrary + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + true + false + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + false + false + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + false + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + true + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + true + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + false + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + false + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + false + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + zlibwapid + zlibwapi + zlibwapi + zlibwapid + zlibwapi + zlibwapi + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions) + + + MultiThreadedDebug + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + EditAndContinue + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + true + .\zlibvc.def + true + true + Windows + false + + + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + true + false + .\zlibvc.def + true + Windows + false + + + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + true + false + .\zlibvc.def + true + Windows + false + + + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + true + .\zlibvc.def + true + true + Windows + MachineX64 + + + cd ..\..\masmx64 +bld_ml64.bat + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + true + false + .\zlibvc.def + true + Windows + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + true + false + .\zlibvc.def + true + Windows + MachineX64 + + + cd ..\..\masmx64 +bld_ml64.bat + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.vcxproj.filters b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.vcxproj.filters new file mode 100644 index 000000000..22786824f --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc10/zlibvc.vcxproj.filters @@ -0,0 +1,118 @@ + + + + + {07934a85-8b61-443d-a0ee-b2eedb74f3cd} + cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90 + + + {1d99675b-433d-4a21-9e50-ed4ab8b19762} + h;hpp;hxx;hm;inl;fi;fd + + + {431c0958-fa71-44d0-9084-2d19d100c0cc} + ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/miniunz.vcxproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/miniunz.vcxproj new file mode 100644 index 000000000..99be63d69 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/miniunz.vcxproj @@ -0,0 +1,314 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {C52F9E7B-498A-42BE-8DB4-85A15694382A} + Win32Proj + + + + Application + MultiByte + v110 + + + Application + Unicode + v110 + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\MiniUnzip$(Configuration)\ + x86\MiniUnzip$(Configuration)\Tmp\ + true + false + x86\MiniUnzip$(Configuration)\ + x86\MiniUnzip$(Configuration)\Tmp\ + false + false + x64\MiniUnzip$(Configuration)\ + x64\MiniUnzip$(Configuration)\Tmp\ + true + false + ia64\MiniUnzip$(Configuration)\ + ia64\MiniUnzip$(Configuration)\Tmp\ + true + false + x64\MiniUnzip$(Configuration)\ + x64\MiniUnzip$(Configuration)\Tmp\ + false + false + ia64\MiniUnzip$(Configuration)\ + ia64\MiniUnzip$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + $(OutDir)miniunz.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)miniunz.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/minizip.vcxproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/minizip.vcxproj new file mode 100644 index 000000000..d6e98f4d5 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/minizip.vcxproj @@ -0,0 +1,311 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B} + Win32Proj + + + + Application + MultiByte + v110 + + + Application + Unicode + v110 + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\MiniZip$(Configuration)\ + x86\MiniZip$(Configuration)\Tmp\ + true + false + x86\MiniZip$(Configuration)\ + x86\MiniZip$(Configuration)\Tmp\ + false + x64\$(Configuration)\ + x64\$(Configuration)\ + true + false + ia64\$(Configuration)\ + ia64\$(Configuration)\ + true + false + x64\$(Configuration)\ + x64\$(Configuration)\ + false + ia64\$(Configuration)\ + ia64\$(Configuration)\ + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + $(OutDir)minizip.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)minizip.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/testzlib.vcxproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/testzlib.vcxproj new file mode 100644 index 000000000..0115dd17b --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/testzlib.vcxproj @@ -0,0 +1,426 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B} + testzlib + Win32Proj + + + + Application + MultiByte + true + v110 + + + Application + MultiByte + true + v110 + + + Application + Unicode + v110 + + + Application + MultiByte + true + + + Application + MultiByte + true + + + Application + MultiByte + + + Application + true + v110 + + + Application + true + v110 + + + Application + v110 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + true + false + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + false + false + x86\TestZlib$(Configuration)\ + x86\TestZlib$(Configuration)\Tmp\ + false + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + true + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + false + false + x64\TestZlib$(Configuration)\ + x64\TestZlib$(Configuration)\Tmp\ + false + ia64\TestZlib$(Configuration)\ + ia64\TestZlib$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + AssemblyAndSourceCode + $(IntDir) + Level3 + ProgramDatabase + + + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)testzlib.exe + true + Console + true + true + false + + + MachineX86 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDebugDLL + false + $(IntDir) + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + + + + + Itanium + + + Disabled + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_DEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + AssemblyAndSourceCode + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + $(OutDir)testzlib.pdb + Console + MachineIA64 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDLL + false + $(IntDir) + + + %(AdditionalDependencies) + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + MachineIA64 + + + + + ..\..\..;%(AdditionalIncludeDirectories) + ASMV;ASMINF;WIN32;ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + Default + MultiThreadedDLL + false + $(IntDir) + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;NDEBUG;_CONSOLE;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + $(OutDir)testzlib.exe + true + Console + true + true + MachineIA64 + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/testzlibdll.vcxproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/testzlibdll.vcxproj new file mode 100644 index 000000000..9d36336eb --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/testzlibdll.vcxproj @@ -0,0 +1,314 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {C52F9E7B-498A-42BE-8DB4-85A15694366A} + Win32Proj + + + + Application + MultiByte + v110 + + + Application + Unicode + v110 + + + Application + MultiByte + + + Application + MultiByte + + + Application + MultiByte + v110 + + + Application + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\TestZlibDll$(Configuration)\ + x86\TestZlibDll$(Configuration)\Tmp\ + true + false + x86\TestZlibDll$(Configuration)\ + x86\TestZlibDll$(Configuration)\Tmp\ + false + false + x64\TestZlibDll$(Configuration)\ + x64\TestZlibDll$(Configuration)\Tmp\ + true + false + ia64\TestZlibDll$(Configuration)\ + ia64\TestZlibDll$(Configuration)\Tmp\ + true + false + x64\TestZlibDll$(Configuration)\ + x64\TestZlibDll$(Configuration)\Tmp\ + false + false + ia64\TestZlibDll$(Configuration)\ + ia64\TestZlibDll$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + false + + + MachineX86 + + + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + Default + MultiThreaded + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x86\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + false + + + MachineX86 + + + + + X64 + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + MachineX64 + + + + + Itanium + + + Disabled + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;_DEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDebugDLL + false + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllDebug\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + $(OutDir)testzlib.pdb + Console + MachineIA64 + + + + + X64 + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + x64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + MachineX64 + + + + + Itanium + + + MaxSpeed + OnlyExplicitInline + true + ..\..\..;..\..\minizip;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;ZLIB_WINAPI;NDEBUG;_CONSOLE;WIN64;%(PreprocessorDefinitions) + true + Default + MultiThreadedDLL + false + true + + + $(IntDir) + Level3 + ProgramDatabase + + + ia64\ZlibDllRelease\zlibwapi.lib;%(AdditionalDependencies) + $(OutDir)testzlibdll.exe + true + Console + true + true + MachineIA64 + + + + + + + + {8fd826f8-3739-44e6-8cc8-997122e53b8d} + + + + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlib.rc b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlib.rc new file mode 100644 index 000000000..d42f191d3 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlib.rc @@ -0,0 +1,32 @@ +#include + +#define IDR_VERSION1 1 +IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE + FILEVERSION 1,2,8,0 + PRODUCTVERSION 1,2,8,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS 0 + FILEOS VOS_DOS_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + + BEGIN + VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0" + VALUE "FileVersion", "1.2.8\0" + VALUE "InternalName", "zlib\0" + VALUE "OriginalFilename", "zlibwapi.dll\0" + VALUE "ProductName", "ZLib.DLL\0" + VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" + VALUE "LegalCopyright", "(C) 1995-2013 Jean-loup Gailly & Mark Adler\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibstat.vcxproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibstat.vcxproj new file mode 100644 index 000000000..64b4d869d --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibstat.vcxproj @@ -0,0 +1,464 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8} + + + + StaticLibrary + false + v110 + + + StaticLibrary + false + v110 + + + StaticLibrary + false + v110 + Unicode + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + + + StaticLibrary + false + v110 + + + StaticLibrary + false + v110 + + + StaticLibrary + false + v110 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x86\ZlibStat$(Configuration)\ + x86\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + x64\ZlibStat$(Configuration)\ + x64\ZlibStat$(Configuration)\Tmp\ + ia64\ZlibStat$(Configuration)\ + ia64\ZlibStat$(Configuration)\Tmp\ + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibstat.lib + true + + + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:X86 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + OldStyle + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + X64 + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:AMD64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + Itanium + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + ZLIB_WINAPI;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibstat.pch + $(IntDir) + $(IntDir) + $(OutDir) + Level3 + true + + + 0x040c + + + /MACHINE:IA64 /NODEFAULTLIB %(AdditionalOptions) + $(OutDir)zlibstat.lib + true + + + + + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibvc.def b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibvc.def new file mode 100644 index 000000000..980fed3a4 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibvc.def @@ -0,0 +1,143 @@ +LIBRARY +; zlib data compression and ZIP file I/O library + +VERSION 1.2.8 + +EXPORTS + adler32 @1 + compress @2 + crc32 @3 + deflate @4 + deflateCopy @5 + deflateEnd @6 + deflateInit2_ @7 + deflateInit_ @8 + deflateParams @9 + deflateReset @10 + deflateSetDictionary @11 + gzclose @12 + gzdopen @13 + gzerror @14 + gzflush @15 + gzopen @16 + gzread @17 + gzwrite @18 + inflate @19 + inflateEnd @20 + inflateInit2_ @21 + inflateInit_ @22 + inflateReset @23 + inflateSetDictionary @24 + inflateSync @25 + uncompress @26 + zlibVersion @27 + gzprintf @28 + gzputc @29 + gzgetc @30 + gzseek @31 + gzrewind @32 + gztell @33 + gzeof @34 + gzsetparams @35 + zError @36 + inflateSyncPoint @37 + get_crc_table @38 + compress2 @39 + gzputs @40 + gzgets @41 + inflateCopy @42 + inflateBackInit_ @43 + inflateBack @44 + inflateBackEnd @45 + compressBound @46 + deflateBound @47 + gzclearerr @48 + gzungetc @49 + zlibCompileFlags @50 + deflatePrime @51 + deflatePending @52 + + unzOpen @61 + unzClose @62 + unzGetGlobalInfo @63 + unzGetCurrentFileInfo @64 + unzGoToFirstFile @65 + unzGoToNextFile @66 + unzOpenCurrentFile @67 + unzReadCurrentFile @68 + unzOpenCurrentFile3 @69 + unztell @70 + unzeof @71 + unzCloseCurrentFile @72 + unzGetGlobalComment @73 + unzStringFileNameCompare @74 + unzLocateFile @75 + unzGetLocalExtrafield @76 + unzOpen2 @77 + unzOpenCurrentFile2 @78 + unzOpenCurrentFilePassword @79 + + zipOpen @80 + zipOpenNewFileInZip @81 + zipWriteInFileInZip @82 + zipCloseFileInZip @83 + zipClose @84 + zipOpenNewFileInZip2 @86 + zipCloseFileInZipRaw @87 + zipOpen2 @88 + zipOpenNewFileInZip3 @89 + + unzGetFilePos @100 + unzGoToFilePos @101 + + fill_win32_filefunc @110 + +; zlibwapi v1.2.4 added: + fill_win32_filefunc64 @111 + fill_win32_filefunc64A @112 + fill_win32_filefunc64W @113 + + unzOpen64 @120 + unzOpen2_64 @121 + unzGetGlobalInfo64 @122 + unzGetCurrentFileInfo64 @124 + unzGetCurrentFileZStreamPos64 @125 + unztell64 @126 + unzGetFilePos64 @127 + unzGoToFilePos64 @128 + + zipOpen64 @130 + zipOpen2_64 @131 + zipOpenNewFileInZip64 @132 + zipOpenNewFileInZip2_64 @133 + zipOpenNewFileInZip3_64 @134 + zipOpenNewFileInZip4_64 @135 + zipCloseFileInZipRaw64 @136 + +; zlib1 v1.2.4 added: + adler32_combine @140 + crc32_combine @142 + deflateSetHeader @144 + deflateTune @145 + gzbuffer @146 + gzclose_r @147 + gzclose_w @148 + gzdirect @149 + gzoffset @150 + inflateGetHeader @156 + inflateMark @157 + inflatePrime @158 + inflateReset2 @159 + inflateUndermine @160 + +; zlib1 v1.2.6 added: + gzgetc_ @161 + inflateResetKeep @163 + deflateResetKeep @164 + +; zlib1 v1.2.7 added: + gzopen_w @165 + +; zlib1 v1.2.8 added: + inflateGetDictionary @166 + gzvprintf @167 diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibvc.sln b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibvc.sln new file mode 100644 index 000000000..b7e381266 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibvc.sln @@ -0,0 +1,117 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "zlibvc.vcxproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "zlibstat.vcxproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlib", "testzlib.vcxproj", "{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlibdll", "testzlibdll.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694366A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "minizip.vcxproj", "{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniunz", "miniunz.vcxproj", "{C52F9E7B-498A-42BE-8DB4-85A15694382A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Itanium = Debug|Itanium + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Itanium = Release|Itanium + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseWithoutAsm|Itanium = ReleaseWithoutAsm|Itanium + ReleaseWithoutAsm|Win32 = ReleaseWithoutAsm|Win32 + ReleaseWithoutAsm|x64 = ReleaseWithoutAsm|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.ActiveCfg = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.Build.0 = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.ActiveCfg = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.Build.0 = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.ActiveCfg = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.ActiveCfg = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.Build.0 = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.ActiveCfg = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.Build.0 = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.Build.0 = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.ActiveCfg = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.Build.0 = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.ActiveCfg = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.ActiveCfg = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.Build.0 = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.ActiveCfg = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.Build.0 = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibvc.vcxproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibvc.vcxproj new file mode 100644 index 000000000..c4cffccf1 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc11/zlibvc.vcxproj @@ -0,0 +1,688 @@ + + + + + Debug + Itanium + + + Debug + Win32 + + + Debug + x64 + + + ReleaseWithoutAsm + Itanium + + + ReleaseWithoutAsm + Win32 + + + ReleaseWithoutAsm + x64 + + + Release + Itanium + + + Release + Win32 + + + Release + x64 + + + + {8FD826F8-3739-44E6-8CC8-997122E53B8D} + + + + DynamicLibrary + false + true + v110 + + + DynamicLibrary + false + true + v110 + + + DynamicLibrary + false + v110 + Unicode + + + DynamicLibrary + false + true + + + DynamicLibrary + false + true + + + DynamicLibrary + false + + + DynamicLibrary + false + true + v110 + + + DynamicLibrary + false + true + v110 + + + DynamicLibrary + false + v110 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30128.1 + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + true + false + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + false + false + x86\ZlibDll$(Configuration)\ + x86\ZlibDll$(Configuration)\Tmp\ + false + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + true + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + true + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + false + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + false + false + x64\ZlibDll$(Configuration)\ + x64\ZlibDll$(Configuration)\Tmp\ + false + false + ia64\ZlibDll$(Configuration)\ + ia64\ZlibDll$(Configuration)\Tmp\ + false + false + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + AllRules.ruleset + + + zlibwapi + zlibwapi + zlibwapi + zlibwapi + zlibwapi + zlibwapi + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + false + + + $(OutDir)zlibwapi.lib + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + false + + + $(OutDir)zlibwapi.lib + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Win32 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;%(PreprocessorDefinitions) + true + + + MultiThreaded + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + /MACHINE:I386 %(AdditionalOptions) + ..\..\masmx86\match686.obj;..\..\masmx86\inffas32.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + false + + + $(OutDir)zlibwapi.lib + + + cd ..\..\masmx86 +bld_ml32.bat + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineX64 + + + cd ..\..\contrib\masmx64 +bld_ml64.bat + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + Disabled + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + + + MultiThreadedDebugDLL + false + $(IntDir)zlibvc.pch + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + ProgramDatabase + + + _DEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + .\zlibvc.def + true + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineX64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + WIN32;_CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + X64 + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;ASMV;ASMINF;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + ..\..\masmx64\gvmat64.obj;..\..\masmx64\inffasx64.obj;%(AdditionalDependencies) + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineX64 + + + cd ..\..\masmx64 +bld_ml64.bat + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + Itanium + $(OutDir)zlibvc.tlb + + + OnlyExplicitInline + ..\..\..;..\..\masmx86;%(AdditionalIncludeDirectories) + _CRT_NONSTDC_NO_DEPRECATE;_CRT_SECURE_NO_DEPRECATE;_CRT_NONSTDC_NO_WARNINGS;ZLIB_WINAPI;WIN64;%(PreprocessorDefinitions) + true + + + MultiThreadedDLL + false + true + $(IntDir)zlibvc.pch + All + $(IntDir) + $(IntDir) + $(OutDir) + + + Level3 + true + + + NDEBUG;%(PreprocessorDefinitions) + 0x040c + + + $(OutDir)zlibwapi.dll + true + false + .\zlibvc.def + $(OutDir)zlibwapi.pdb + true + $(OutDir)zlibwapi.map + Windows + $(OutDir)zlibwapi.lib + MachineIA64 + + + + + + + + + + + + + + true + true + true + true + true + true + + + + + + + + + + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + + + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + %(AdditionalIncludeDirectories) + ZLIB_INTERNAL;%(PreprocessorDefinitions) + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/miniunz.vcproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/miniunz.vcproj new file mode 100644 index 000000000..038a9e5fa --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/miniunz.vcproj @@ -0,0 +1,565 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/minizip.vcproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/minizip.vcproj new file mode 100644 index 000000000..ad4023991 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/minizip.vcproj @@ -0,0 +1,562 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/testzlib.vcproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/testzlib.vcproj new file mode 100644 index 000000000..c9f19d24e --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/testzlib.vcproj @@ -0,0 +1,852 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/testzlibdll.vcproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/testzlibdll.vcproj new file mode 100644 index 000000000..d7530fd7d --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/testzlibdll.vcproj @@ -0,0 +1,565 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlib.rc b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlib.rc new file mode 100644 index 000000000..d42f191d3 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlib.rc @@ -0,0 +1,32 @@ +#include + +#define IDR_VERSION1 1 +IDR_VERSION1 VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE + FILEVERSION 1,2,8,0 + PRODUCTVERSION 1,2,8,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK + FILEFLAGS 0 + FILEOS VOS_DOS_WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + + BEGIN + VALUE "FileDescription", "zlib data compression and ZIP file I/O library\0" + VALUE "FileVersion", "1.2.8\0" + VALUE "InternalName", "zlib\0" + VALUE "OriginalFilename", "zlibwapi.dll\0" + VALUE "ProductName", "ZLib.DLL\0" + VALUE "Comments","DLL support by Alessandro Iacopetti & Gilles Vollant\0" + VALUE "LegalCopyright", "(C) 1995-2013 Jean-loup Gailly & Mark Adler\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibstat.vcproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibstat.vcproj new file mode 100644 index 000000000..d4ffb46b2 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibstat.vcproj @@ -0,0 +1,835 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibvc.def b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibvc.def new file mode 100644 index 000000000..980fed3a4 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibvc.def @@ -0,0 +1,143 @@ +LIBRARY +; zlib data compression and ZIP file I/O library + +VERSION 1.2.8 + +EXPORTS + adler32 @1 + compress @2 + crc32 @3 + deflate @4 + deflateCopy @5 + deflateEnd @6 + deflateInit2_ @7 + deflateInit_ @8 + deflateParams @9 + deflateReset @10 + deflateSetDictionary @11 + gzclose @12 + gzdopen @13 + gzerror @14 + gzflush @15 + gzopen @16 + gzread @17 + gzwrite @18 + inflate @19 + inflateEnd @20 + inflateInit2_ @21 + inflateInit_ @22 + inflateReset @23 + inflateSetDictionary @24 + inflateSync @25 + uncompress @26 + zlibVersion @27 + gzprintf @28 + gzputc @29 + gzgetc @30 + gzseek @31 + gzrewind @32 + gztell @33 + gzeof @34 + gzsetparams @35 + zError @36 + inflateSyncPoint @37 + get_crc_table @38 + compress2 @39 + gzputs @40 + gzgets @41 + inflateCopy @42 + inflateBackInit_ @43 + inflateBack @44 + inflateBackEnd @45 + compressBound @46 + deflateBound @47 + gzclearerr @48 + gzungetc @49 + zlibCompileFlags @50 + deflatePrime @51 + deflatePending @52 + + unzOpen @61 + unzClose @62 + unzGetGlobalInfo @63 + unzGetCurrentFileInfo @64 + unzGoToFirstFile @65 + unzGoToNextFile @66 + unzOpenCurrentFile @67 + unzReadCurrentFile @68 + unzOpenCurrentFile3 @69 + unztell @70 + unzeof @71 + unzCloseCurrentFile @72 + unzGetGlobalComment @73 + unzStringFileNameCompare @74 + unzLocateFile @75 + unzGetLocalExtrafield @76 + unzOpen2 @77 + unzOpenCurrentFile2 @78 + unzOpenCurrentFilePassword @79 + + zipOpen @80 + zipOpenNewFileInZip @81 + zipWriteInFileInZip @82 + zipCloseFileInZip @83 + zipClose @84 + zipOpenNewFileInZip2 @86 + zipCloseFileInZipRaw @87 + zipOpen2 @88 + zipOpenNewFileInZip3 @89 + + unzGetFilePos @100 + unzGoToFilePos @101 + + fill_win32_filefunc @110 + +; zlibwapi v1.2.4 added: + fill_win32_filefunc64 @111 + fill_win32_filefunc64A @112 + fill_win32_filefunc64W @113 + + unzOpen64 @120 + unzOpen2_64 @121 + unzGetGlobalInfo64 @122 + unzGetCurrentFileInfo64 @124 + unzGetCurrentFileZStreamPos64 @125 + unztell64 @126 + unzGetFilePos64 @127 + unzGoToFilePos64 @128 + + zipOpen64 @130 + zipOpen2_64 @131 + zipOpenNewFileInZip64 @132 + zipOpenNewFileInZip2_64 @133 + zipOpenNewFileInZip3_64 @134 + zipOpenNewFileInZip4_64 @135 + zipCloseFileInZipRaw64 @136 + +; zlib1 v1.2.4 added: + adler32_combine @140 + crc32_combine @142 + deflateSetHeader @144 + deflateTune @145 + gzbuffer @146 + gzclose_r @147 + gzclose_w @148 + gzdirect @149 + gzoffset @150 + inflateGetHeader @156 + inflateMark @157 + inflatePrime @158 + inflateReset2 @159 + inflateUndermine @160 + +; zlib1 v1.2.6 added: + gzgetc_ @161 + inflateResetKeep @163 + deflateResetKeep @164 + +; zlib1 v1.2.7 added: + gzopen_w @165 + +; zlib1 v1.2.8 added: + inflateGetDictionary @166 + gzvprintf @167 diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibvc.sln b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibvc.sln new file mode 100644 index 000000000..75c64c3f4 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibvc.sln @@ -0,0 +1,144 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibvc", "zlibvc.vcproj", "{8FD826F8-3739-44E6-8CC8-997122E53B8D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlibstat", "zlibstat.vcproj", "{745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testzlib", "testzlib.vcproj", "{AA6666AA-E09F-4135-9C0C-4FE50C3C654B}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestZlibDll", "testzlibdll.vcproj", "{C52F9E7B-498A-42BE-8DB4-85A15694366A}" + ProjectSection(ProjectDependencies) = postProject + {8FD826F8-3739-44E6-8CC8-997122E53B8D} = {8FD826F8-3739-44E6-8CC8-997122E53B8D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "minizip", "minizip.vcproj", "{48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}" + ProjectSection(ProjectDependencies) = postProject + {8FD826F8-3739-44E6-8CC8-997122E53B8D} = {8FD826F8-3739-44E6-8CC8-997122E53B8D} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "miniunz", "miniunz.vcproj", "{C52F9E7B-498A-42BE-8DB4-85A15694382A}" + ProjectSection(ProjectDependencies) = postProject + {8FD826F8-3739-44E6-8CC8-997122E53B8D} = {8FD826F8-3739-44E6-8CC8-997122E53B8D} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Itanium = Debug|Itanium + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Itanium = Release|Itanium + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + ReleaseWithoutAsm|Itanium = ReleaseWithoutAsm|Itanium + ReleaseWithoutAsm|Win32 = ReleaseWithoutAsm|Win32 + ReleaseWithoutAsm|x64 = ReleaseWithoutAsm|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.ActiveCfg = Debug|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Itanium.Build.0 = Debug|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.ActiveCfg = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|Win32.Build.0 = Debug|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.ActiveCfg = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Debug|x64.Build.0 = Debug|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.ActiveCfg = Release|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Itanium.Build.0 = Release|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.ActiveCfg = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|Win32.Build.0 = Release|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.ActiveCfg = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.Release|x64.Build.0 = Release|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {8FD826F8-3739-44E6-8CC8-997122E53B8D}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.ActiveCfg = Debug|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Itanium.Build.0 = Debug|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.ActiveCfg = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|Win32.Build.0 = Debug|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.ActiveCfg = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Debug|x64.Build.0 = Debug|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.ActiveCfg = Release|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Itanium.Build.0 = Release|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.ActiveCfg = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|Win32.Build.0 = Release|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.ActiveCfg = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.Release|x64.Build.0 = Release|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {745DEC58-EBB3-47A9-A9B8-4C6627C01BF8}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.Build.0 = Debug|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.Build.0 = Release|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = ReleaseWithoutAsm|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.Build.0 = ReleaseWithoutAsm|Itanium + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.Build.0 = ReleaseWithoutAsm|Win32 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = ReleaseWithoutAsm|x64 + {AA6666AA-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.Build.0 = ReleaseWithoutAsm|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.ActiveCfg = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Itanium.Build.0 = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694366A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.ActiveCfg = Debug|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Itanium.Build.0 = Debug|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.ActiveCfg = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|Win32.Build.0 = Debug|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.ActiveCfg = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Debug|x64.Build.0 = Debug|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.ActiveCfg = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Itanium.Build.0 = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|Win32.Build.0 = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.ActiveCfg = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.Release|x64.Build.0 = Release|x64 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {48CDD9DC-E09F-4135-9C0C-4FE50C3C654B}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.ActiveCfg = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Itanium.Build.0 = Debug|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.ActiveCfg = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|Win32.Build.0 = Debug|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.ActiveCfg = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Debug|x64.Build.0 = Debug|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|Win32.Build.0 = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.ActiveCfg = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.Release|x64.Build.0 = Release|x64 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.ActiveCfg = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Itanium.Build.0 = Release|Itanium + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|Win32.ActiveCfg = Release|Win32 + {C52F9E7B-498A-42BE-8DB4-85A15694382A}.ReleaseWithoutAsm|x64.ActiveCfg = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibvc.vcproj b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibvc.vcproj new file mode 100644 index 000000000..95bb241f3 --- /dev/null +++ b/test/zlib/zlib-1.2.8/contrib/vstudio/vc9/zlibvc.vcproj @@ -0,0 +1,1156 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/zlib/zlib-1.2.8/crc32.c b/test/zlib/zlib-1.2.8/crc32.c new file mode 100644 index 000000000..979a7190a --- /dev/null +++ b/test/zlib/zlib-1.2.8/crc32.c @@ -0,0 +1,425 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + * + * Thanks to Rodney Brown for his contribution of faster + * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing + * tables for updating the shift register in one step with three exclusive-ors + * instead of four steps with four exclusive-ors. This results in about a + * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. + */ + +/* @(#) $Id$ */ + +/* + Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore + protection on the static variables used to control the first-use generation + of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should + first call get_crc_table() to initialize the tables before allowing more than + one thread to use crc32(). + + DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. + */ + +#ifdef MAKECRCH +# include +# ifndef DYNAMIC_CRC_TABLE +# define DYNAMIC_CRC_TABLE +# endif /* !DYNAMIC_CRC_TABLE */ +#endif /* MAKECRCH */ + +#include "zutil.h" /* for STDC and FAR definitions */ + +#define local static + +/* Definitions for doing the crc four data bytes at a time. */ +#if !defined(NOBYFOUR) && defined(Z_U4) +# define BYFOUR +#endif +#ifdef BYFOUR + local unsigned long crc32_little OF((unsigned long, + const unsigned char FAR *, unsigned)); + local unsigned long crc32_big OF((unsigned long, + const unsigned char FAR *, unsigned)); +# define TBLS 8 +#else +# define TBLS 1 +#endif /* BYFOUR */ + +/* Local functions for crc concatenation */ +local unsigned long gf2_matrix_times OF((unsigned long *mat, + unsigned long vec)); +local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); +local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); + + +#ifdef DYNAMIC_CRC_TABLE + +local volatile int crc_table_empty = 1; +local z_crc_t FAR crc_table[TBLS][256]; +local void make_crc_table OF((void)); +#ifdef MAKECRCH + local void write_table OF((FILE *, const z_crc_t FAR *)); +#endif /* MAKECRCH */ +/* + Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The first table is simply the CRC of all possible eight bit values. This is + all the information needed to generate CRCs on data a byte at a time for all + combinations of CRC register values and incoming bytes. The remaining tables + allow for word-at-a-time CRC calculation for both big-endian and little- + endian machines, where a word is four bytes. +*/ +local void make_crc_table() +{ + z_crc_t c; + int n, k; + z_crc_t poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static volatile int first = 1; /* flag to limit concurrent making */ + static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* See if another task is already doing this (not thread-safe, but better + than nothing -- significantly reduces duration of vulnerability in + case the advice about DYNAMIC_CRC_TABLE is ignored) */ + if (first) { + first = 0; + + /* make exclusive-or pattern from polynomial (0xedb88320UL) */ + poly = 0; + for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) + poly |= (z_crc_t)1 << (31 - p[n]); + + /* generate a crc for every 8-bit value */ + for (n = 0; n < 256; n++) { + c = (z_crc_t)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[0][n] = c; + } + +#ifdef BYFOUR + /* generate crc for each value followed by one, two, and three zeros, + and then the byte reversal of those as well as the first table */ + for (n = 0; n < 256; n++) { + c = crc_table[0][n]; + crc_table[4][n] = ZSWAP32(c); + for (k = 1; k < 4; k++) { + c = crc_table[0][c & 0xff] ^ (c >> 8); + crc_table[k][n] = c; + crc_table[k + 4][n] = ZSWAP32(c); + } + } +#endif /* BYFOUR */ + + crc_table_empty = 0; + } + else { /* not first */ + /* wait for the other guy to finish (not efficient, but rare) */ + while (crc_table_empty) + ; + } + +#ifdef MAKECRCH + /* write out CRC tables to crc32.h */ + { + FILE *out; + + out = fopen("crc32.h", "w"); + if (out == NULL) return; + fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); + fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); + fprintf(out, "local const z_crc_t FAR "); + fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); + write_table(out, crc_table[0]); +# ifdef BYFOUR + fprintf(out, "#ifdef BYFOUR\n"); + for (k = 1; k < 8; k++) { + fprintf(out, " },\n {\n"); + write_table(out, crc_table[k]); + } + fprintf(out, "#endif\n"); +# endif /* BYFOUR */ + fprintf(out, " }\n};\n"); + fclose(out); + } +#endif /* MAKECRCH */ +} + +#ifdef MAKECRCH +local void write_table(out, table) + FILE *out; + const z_crc_t FAR *table; +{ + int n; + + for (n = 0; n < 256; n++) + fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", + (unsigned long)(table[n]), + n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); +} +#endif /* MAKECRCH */ + +#else /* !DYNAMIC_CRC_TABLE */ +/* ======================================================================== + * Tables of CRC-32s of all single-byte values, made by make_crc_table(). + */ +#include "crc32.h" +#endif /* DYNAMIC_CRC_TABLE */ + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const z_crc_t FAR * ZEXPORT get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + return (const z_crc_t FAR *)crc_table; +} + +/* ========================================================================= */ +#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) +#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 + +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + uInt len; +{ + if (buf == Z_NULL) return 0UL; + +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif /* DYNAMIC_CRC_TABLE */ + +#ifdef BYFOUR + if (sizeof(void *) == sizeof(ptrdiff_t)) { + z_crc_t endian; + + endian = 1; + if (*((unsigned char *)(&endian))) + return crc32_little(crc, buf, len); + else + return crc32_big(crc, buf, len); + } +#endif /* BYFOUR */ + crc = crc ^ 0xffffffffUL; + while (len >= 8) { + DO8; + len -= 8; + } + if (len) do { + DO1; + } while (--len); + return crc ^ 0xffffffffUL; +} + +#ifdef BYFOUR + +/* ========================================================================= */ +#define DOLIT4 c ^= *buf4++; \ + c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ + crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] +#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 + +/* ========================================================================= */ +local unsigned long crc32_little(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register z_crc_t c; + register const z_crc_t FAR *buf4; + + c = (z_crc_t)crc; + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + len--; + } + + buf4 = (const z_crc_t FAR *)(const void FAR *)buf; + while (len >= 32) { + DOLIT32; + len -= 32; + } + while (len >= 4) { + DOLIT4; + len -= 4; + } + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); + } while (--len); + c = ~c; + return (unsigned long)c; +} + +/* ========================================================================= */ +#define DOBIG4 c ^= *++buf4; \ + c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ + crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] +#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 + +/* ========================================================================= */ +local unsigned long crc32_big(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + unsigned len; +{ + register z_crc_t c; + register const z_crc_t FAR *buf4; + + c = ZSWAP32((z_crc_t)crc); + c = ~c; + while (len && ((ptrdiff_t)buf & 3)) { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + len--; + } + + buf4 = (const z_crc_t FAR *)(const void FAR *)buf; + buf4--; + while (len >= 32) { + DOBIG32; + len -= 32; + } + while (len >= 4) { + DOBIG4; + len -= 4; + } + buf4++; + buf = (const unsigned char FAR *)buf4; + + if (len) do { + c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); + } while (--len); + c = ~c; + return (unsigned long)(ZSWAP32(c)); +} + +#endif /* BYFOUR */ + +#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ + +/* ========================================================================= */ +local unsigned long gf2_matrix_times(mat, vec) + unsigned long *mat; + unsigned long vec; +{ + unsigned long sum; + + sum = 0; + while (vec) { + if (vec & 1) + sum ^= *mat; + vec >>= 1; + mat++; + } + return sum; +} + +/* ========================================================================= */ +local void gf2_matrix_square(square, mat) + unsigned long *square; + unsigned long *mat; +{ + int n; + + for (n = 0; n < GF2_DIM; n++) + square[n] = gf2_matrix_times(mat, mat[n]); +} + +/* ========================================================================= */ +local uLong crc32_combine_(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + int n; + unsigned long row; + unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ + unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ + + /* degenerate case (also disallow negative lengths) */ + if (len2 <= 0) + return crc1; + + /* put operator for one zero bit in odd */ + odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ + row = 1; + for (n = 1; n < GF2_DIM; n++) { + odd[n] = row; + row <<= 1; + } + + /* put operator for two zero bits in even */ + gf2_matrix_square(even, odd); + + /* put operator for four zero bits in odd */ + gf2_matrix_square(odd, even); + + /* apply len2 zeros to crc1 (first square will put the operator for one + zero byte, eight zero bits, in even) */ + do { + /* apply zeros operator for this bit of len2 */ + gf2_matrix_square(even, odd); + if (len2 & 1) + crc1 = gf2_matrix_times(even, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + if (len2 == 0) + break; + + /* another iteration of the loop with odd and even swapped */ + gf2_matrix_square(odd, even); + if (len2 & 1) + crc1 = gf2_matrix_times(odd, crc1); + len2 >>= 1; + + /* if no more bits set, then done */ + } while (len2 != 0); + + /* return combined crc */ + crc1 ^= crc2; + return crc1; +} + +/* ========================================================================= */ +uLong ZEXPORT crc32_combine(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} + +uLong ZEXPORT crc32_combine64(crc1, crc2, len2) + uLong crc1; + uLong crc2; + z_off64_t len2; +{ + return crc32_combine_(crc1, crc2, len2); +} diff --git a/test/zlib/zlib-1.2.8/crc32.h b/test/zlib/zlib-1.2.8/crc32.h new file mode 100644 index 000000000..9e0c77810 --- /dev/null +++ b/test/zlib/zlib-1.2.8/crc32.h @@ -0,0 +1,441 @@ +/* crc32.h -- tables for rapid CRC calculation + * Generated automatically by crc32.c + */ + +local const z_crc_t FAR crc_table[TBLS][256] = +{ + { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dUL +#ifdef BYFOUR + }, + { + 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, + 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, + 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, + 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, + 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, + 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, + 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, + 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, + 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, + 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, + 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, + 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, + 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, + 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, + 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, + 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, + 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, + 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, + 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, + 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, + 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, + 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, + 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, + 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, + 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, + 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, + 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, + 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, + 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, + 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, + 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, + 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, + 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, + 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, + 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, + 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, + 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, + 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, + 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, + 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, + 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, + 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, + 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, + 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, + 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, + 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, + 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, + 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, + 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, + 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, + 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, + 0x9324fd72UL + }, + { + 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, + 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, + 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, + 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, + 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, + 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, + 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, + 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, + 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, + 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, + 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, + 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, + 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, + 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, + 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, + 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, + 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, + 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, + 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, + 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, + 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, + 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, + 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, + 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, + 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, + 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, + 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, + 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, + 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, + 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, + 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, + 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, + 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, + 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, + 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, + 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, + 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, + 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, + 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, + 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, + 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, + 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, + 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, + 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, + 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, + 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, + 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, + 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, + 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, + 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, + 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, + 0xbe9834edUL + }, + { + 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, + 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, + 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, + 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, + 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, + 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, + 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, + 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, + 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, + 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, + 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, + 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, + 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, + 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, + 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, + 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, + 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, + 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, + 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, + 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, + 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, + 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, + 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, + 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, + 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, + 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, + 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, + 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, + 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, + 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, + 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, + 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, + 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, + 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, + 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, + 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, + 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, + 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, + 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, + 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, + 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, + 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, + 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, + 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, + 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, + 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, + 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, + 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, + 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, + 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, + 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, + 0xde0506f1UL + }, + { + 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, + 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, + 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, + 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, + 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, + 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, + 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, + 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, + 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, + 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, + 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, + 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, + 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, + 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, + 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, + 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, + 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, + 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, + 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, + 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, + 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, + 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, + 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, + 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, + 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, + 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, + 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, + 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, + 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, + 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, + 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, + 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, + 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, + 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, + 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, + 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, + 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, + 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, + 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, + 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, + 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, + 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, + 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, + 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, + 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, + 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, + 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, + 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, + 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, + 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, + 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, + 0x8def022dUL + }, + { + 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, + 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, + 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, + 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, + 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, + 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, + 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, + 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, + 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, + 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, + 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, + 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, + 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, + 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, + 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, + 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, + 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, + 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, + 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, + 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, + 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, + 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, + 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, + 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, + 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, + 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, + 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, + 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, + 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, + 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, + 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, + 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, + 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, + 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, + 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, + 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, + 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, + 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, + 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, + 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, + 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, + 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, + 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, + 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, + 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, + 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, + 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, + 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, + 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, + 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, + 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, + 0x72fd2493UL + }, + { + 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, + 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, + 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, + 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, + 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, + 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, + 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, + 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, + 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, + 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, + 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, + 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, + 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, + 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, + 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, + 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, + 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, + 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, + 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, + 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, + 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, + 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, + 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, + 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, + 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, + 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, + 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, + 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, + 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, + 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, + 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, + 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, + 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, + 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, + 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, + 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, + 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, + 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, + 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, + 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, + 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, + 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, + 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, + 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, + 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, + 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, + 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, + 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, + 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, + 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, + 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, + 0xed3498beUL + }, + { + 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, + 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, + 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, + 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, + 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, + 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, + 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, + 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, + 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, + 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, + 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, + 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, + 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, + 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, + 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, + 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, + 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, + 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, + 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, + 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, + 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, + 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, + 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, + 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, + 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, + 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, + 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, + 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, + 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, + 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, + 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, + 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, + 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, + 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, + 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, + 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, + 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, + 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, + 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, + 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, + 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, + 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, + 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, + 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, + 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, + 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, + 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, + 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, + 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, + 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, + 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, + 0xf10605deUL +#endif + } +}; diff --git a/test/zlib/zlib-1.2.8/deflate.c b/test/zlib/zlib-1.2.8/deflate.c new file mode 100644 index 000000000..696957705 --- /dev/null +++ b/test/zlib/zlib-1.2.8/deflate.c @@ -0,0 +1,1967 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". + * Available in http://tools.ietf.org/html/rfc1951 + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* @(#) $Id$ */ + +#include "deflate.h" + +const char deflate_copyright[] = + " deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +#ifndef FASTEST +local block_state deflate_slow OF((deflate_state *s, int flush)); +#endif +local block_state deflate_rle OF((deflate_state *s, int flush)); +local block_state deflate_huff OF((deflate_state *s, int flush)); +local void lm_init OF((deflate_state *s)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ + uInt longest_match OF((deflate_state *s, IPos cur_match)); +#else +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +#endif + +#ifdef DEBUG +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +#ifdef FASTEST +local const config configuration_table[2] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ +#else +local const config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ +#endif + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +#ifndef NO_DUMMY_DECL +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ +#endif + +/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ +#define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0)) + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * If this file is compiled with -DFASTEST, the compression level is forced + * to 1, and no hash chains are maintained. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#ifdef FASTEST +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#else +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) +#endif + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +int ZEXPORT deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int wrap = 1; + static const char my_version[] = ZLIB_VERSION; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != my_version[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + + if (windowBits < 0) { /* suppress zlib wrapper */ + wrap = 0; + windowBits = -windowBits; + } +#ifdef GZIP + else if (windowBits > 15) { + wrap = 2; /* write gzip wrapper instead */ + windowBits -= 16; + } +#endif + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->wrap = wrap; + s->gzhead = Z_NULL; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->high_water = 0; /* nothing written to s->window yet */ + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + s->status = FINISH_STATE; + strm->msg = ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt str, n; + int wrap; + unsigned avail; + z_const unsigned char *next; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) + return Z_STREAM_ERROR; + s = strm->state; + wrap = s->wrap; + if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) + return Z_STREAM_ERROR; + + /* when using zlib wrappers, compute Adler-32 for provided dictionary */ + if (wrap == 1) + strm->adler = adler32(strm->adler, dictionary, dictLength); + s->wrap = 0; /* avoid computing Adler-32 in read_buf */ + + /* if dictionary would fill window, just replace the history */ + if (dictLength >= s->w_size) { + if (wrap == 0) { /* already empty otherwise */ + CLEAR_HASH(s); + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } + dictionary += dictLength - s->w_size; /* use the tail */ + dictLength = s->w_size; + } + + /* insert dictionary into window and hash */ + avail = strm->avail_in; + next = strm->next_in; + strm->avail_in = dictLength; + strm->next_in = (z_const Bytef *)dictionary; + fill_window(s); + while (s->lookahead >= MIN_MATCH) { + str = s->strstart; + n = s->lookahead - (MIN_MATCH-1); + do { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + } while (--n); + s->strstart = str; + s->lookahead = MIN_MATCH-1; + fill_window(s); + } + s->strstart += s->lookahead; + s->block_start = (long)s->strstart; + s->insert = s->lookahead; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + strm->next_in = next; + strm->avail_in = avail; + s->wrap = wrap; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateResetKeep (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + return Z_STREAM_ERROR; + } + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->wrap < 0) { + s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ + } + s->status = s->wrap ? INIT_STATE : BUSY_STATE; + strm->adler = +#ifdef GZIP + s->wrap == 2 ? crc32(0L, Z_NULL, 0) : +#endif + adler32(0L, Z_NULL, 0); + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateReset (strm) + z_streamp strm; +{ + int ret; + + ret = deflateResetKeep(strm); + if (ret == Z_OK) + lm_init(strm->state); + return ret; +} + +/* ========================================================================= */ +int ZEXPORT deflateSetHeader (strm, head) + z_streamp strm; + gz_headerp head; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm->state->wrap != 2) return Z_STREAM_ERROR; + strm->state->gzhead = head; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePending (strm, pending, bits) + unsigned *pending; + int *bits; + z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (pending != Z_NULL) + *pending = strm->state->pending; + if (bits != Z_NULL) + *bits = strm->state->bi_valid; + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflatePrime (strm, bits, value) + z_streamp strm; + int bits; + int value; +{ + deflate_state *s; + int put; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) + return Z_BUF_ERROR; + do { + put = Buf_size - s->bi_valid; + if (put > bits) + put = bits; + s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); + s->bi_valid += put; + _tr_flush_bits(s); + value >>= put; + bits -= put; + } while (bits); + return Z_OK; +} + +/* ========================================================================= */ +int ZEXPORT deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + +#ifdef FASTEST + if (level != 0) level = 1; +#else + if (level == Z_DEFAULT_COMPRESSION) level = 6; +#endif + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if ((strategy != s->strategy || func != configuration_table[level].func) && + strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_BLOCK); + if (err == Z_BUF_ERROR && s->pending == 0) + err = Z_OK; + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= */ +int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) + z_streamp strm; + int good_length; + int max_lazy; + int nice_length; + int max_chain; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + s->good_match = good_length; + s->max_lazy_match = max_lazy; + s->nice_match = nice_length; + s->max_chain_length = max_chain; + return Z_OK; +} + +/* ========================================================================= + * For the default windowBits of 15 and memLevel of 8, this function returns + * a close to exact, as well as small, upper bound on the compressed size. + * They are coded as constants here for a reason--if the #define's are + * changed, then this function needs to be changed as well. The return + * value for 15 and 8 only works for those exact settings. + * + * For any setting other than those defaults for windowBits and memLevel, + * the value returned is a conservative worst case for the maximum expansion + * resulting from using fixed blocks instead of stored blocks, which deflate + * can emit on compressed data for some combinations of the parameters. + * + * This function could be more sophisticated to provide closer upper bounds for + * every combination of windowBits and memLevel. But even the conservative + * upper bound of about 14% expansion does not seem onerous for output buffer + * allocation. + */ +uLong ZEXPORT deflateBound(strm, sourceLen) + z_streamp strm; + uLong sourceLen; +{ + deflate_state *s; + uLong complen, wraplen; + Bytef *str; + + /* conservative upper bound for compressed data */ + complen = sourceLen + + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; + + /* if can't get parameters, return conservative bound plus zlib wrapper */ + if (strm == Z_NULL || strm->state == Z_NULL) + return complen + 6; + + /* compute wrapper length */ + s = strm->state; + switch (s->wrap) { + case 0: /* raw deflate */ + wraplen = 0; + break; + case 1: /* zlib wrapper */ + wraplen = 6 + (s->strstart ? 4 : 0); + break; + case 2: /* gzip wrapper */ + wraplen = 18; + if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ + if (s->gzhead->extra != Z_NULL) + wraplen += 2 + s->gzhead->extra_len; + str = s->gzhead->name; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + str = s->gzhead->comment; + if (str != Z_NULL) + do { + wraplen++; + } while (*str++); + if (s->gzhead->hcrc) + wraplen += 2; + } + break; + default: /* for compiler happiness */ + wraplen = 6; + } + + /* if not default parameters, return conservative bound */ + if (s->w_bits != 15 || s->hash_bits != 8 + 7) + return complen + wraplen; + + /* default settings: return tight bound for that case */ + return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + + (sourceLen >> 25) + 13 - 6 + wraplen; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len; + deflate_state *s = strm->state; + + _tr_flush_bits(s); + len = s->pending; + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, s->pending_out, len); + strm->next_out += len; + s->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + s->pending -= len; + if (s->pending == 0) { + s->pending_out = s->pending_buf; + } +} + +/* ========================================================================= */ +int ZEXPORT deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_BLOCK || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the header */ + if (s->status == INIT_STATE) { +#ifdef GZIP + if (s->wrap == 2) { + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == Z_NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != Z_NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + else +#endif + { + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + } + } +#ifdef GZIP + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != Z_NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + + while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) + break; + } + put_byte(s, s->gzhead->extra[s->gzindex]); + s->gzindex++; + } + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (s->gzindex == s->gzhead->extra_len) { + s->gzindex = 0; + s->status = NAME_STATE; + } + } + else + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != Z_NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) { + s->gzindex = 0; + s->status = COMMENT_STATE; + } + } + else + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != Z_NULL) { + uInt beg = s->pending; /* start of bytes to update crc */ + int val; + + do { + if (s->pending == s->pending_buf_size) { + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + flush_pending(strm); + beg = s->pending; + if (s->pending == s->pending_buf_size) { + val = 1; + break; + } + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + if (s->gzhead->hcrc && s->pending > beg) + strm->adler = crc32(strm->adler, s->pending_buf + beg, + s->pending - beg); + if (val == 0) + s->status = HCRC_STATE; + } + else + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) + flush_pending(strm); + if (s->pending + 2 <= s->pending_buf_size) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + } + } + else + s->status = BUSY_STATE; + } +#endif + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUF_ERROR. + */ + } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : + (s->strategy == Z_RLE ? deflate_rle(s, flush) : + (*(configuration_table[s->level].func))(s, flush)); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + if (s->lookahead == 0) { + s->strstart = 0; + s->block_start = 0L; + s->insert = 0; + } + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->wrap <= 0) return Z_STREAM_END; + + /* Write the trailer */ +#ifdef GZIP + if (s->wrap == 2) { + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); + put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); + put_byte(s, (Byte)(strm->total_in & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); + put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); + } + else +#endif + { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +int ZEXPORT deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + status = strm->state->status; + if (status != INIT_STATE && + status != EXTRA_STATE && + status != NAME_STATE && + status != COMMENT_STATE && + status != HCRC_STATE && + status != BUSY_STATE && + status != FINISH_STATE) { + return Z_STREAM_ERROR; + } + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= + * Copy the source state to the destination state. + * To simplify the source, this is not supported for 16-bit MSDOS (which + * doesn't have enough memory anyway to duplicate compression states). + */ +int ZEXPORT deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ +#ifdef MAXSEG_64K + return Z_STREAM_ERROR; +#else + deflate_state *ds; + deflate_state *ss; + ushf *overlay; + + + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + + ss = source->state; + + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + + ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); + if (ds == Z_NULL) return Z_MEM_ERROR; + dest->state = (struct internal_state FAR *) ds; + zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); + ds->strm = dest; + + ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); + ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); + ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); + overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); + ds->pending_buf = (uchf *) overlay; + + if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || + ds->pending_buf == Z_NULL) { + deflateEnd (dest); + return Z_MEM_ERROR; + } + /* following zmemcpy do not work for 16-bit MSDOS */ + zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); + zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); + zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); + zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); + + ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); + ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); + ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; + + ds->l_desc.dyn_tree = ds->dyn_ltree; + ds->d_desc.dyn_tree = ds->dyn_dtree; + ds->bl_desc.dyn_tree = ds->bl_tree; + + return Z_OK; +#endif /* MAXSEG_64K */ +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + Bytef *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + zmemcpy(buf, strm->next_in, len); + if (strm->state->wrap == 1) { + strm->adler = adler32(strm->adler, buf, len); + } +#ifdef GZIP + else if (strm->state->wrap == 2) { + strm->adler = crc32(strm->adler, buf, len); + } +#endif + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->insert = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifndef FASTEST +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +#endif +} + +#ifndef FASTEST +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2. Note that the checks below + * for insufficient lookahead only occur occasionally for performance + * reasons. Therefore uninitialized memory will be accessed, and + * conditional jumps will be made that depend on those values. + * However the length of the match is limited to the lookahead, so + * the output of deflate is not affected by the uninitialized values. + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return (uInt)best_len; + return s->lookahead; +} +#endif /* ASMV */ + +#else /* FASTEST */ + +/* --------------------------------------------------------------------------- + * Optimized version for FASTEST only + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + Assert(cur_match < s->strstart, "no future"); + + match = s->window + cur_match; + + /* Return failure if the match length is less than 2: + */ + if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match += 2; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + + if (len < MIN_MATCH) return MIN_MATCH - 1; + + s->match_start = cur_match; + return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; +} + +#endif /* FASTEST */ + +#ifdef DEBUG +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp(s->window + match, + s->window + start, length) != EQUAL) { + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (z_verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif /* DEBUG */ + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (sizeof(int) <= 2) { + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if + * strstart == 0 && lookahead == 1 (input done a byte at time) + */ + more--; + } + } + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage). We slide even when level == 0 + to keep the hash table consistent if we switch back to level > 0 + later. (Using level 0 permanently is not an optimal usage of + zlib, so we don't care about this pathological case.) + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif + more += wsize; + } + if (s->strm->avail_in == 0) break; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead + s->insert >= MIN_MATCH) { + uInt str = s->strstart - s->insert; + s->ins_h = s->window[str]; + UPDATE_HASH(s, s->ins_h, s->window[str + 1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + while (s->insert) { + UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); +#ifndef FASTEST + s->prev[str & s->w_mask] = s->head[s->ins_h]; +#endif + s->head[s->ins_h] = (Pos)str; + str++; + s->insert--; + if (s->lookahead + s->insert < MIN_MATCH) + break; + } + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); + + /* If the WIN_INIT bytes after the end of the current data have never been + * written, then zero those bytes in order to avoid memory check reports of + * the use of uninitialized (or uninitialised as Julian writes) bytes by + * the longest match routines. Update the high water mark for the next + * time through here. WIN_INIT is set to MAX_MATCH since the longest match + * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. + */ + if (s->high_water < s->window_size) { + ulg curr = s->strstart + (ulg)(s->lookahead); + ulg init; + + if (s->high_water < curr) { + /* Previous high water mark below current data -- zero WIN_INIT + * bytes or up to end of window, whichever is less. + */ + init = s->window_size - curr; + if (init > WIN_INIT) + init = WIN_INIT; + zmemzero(s->window + curr, (unsigned)init); + s->high_water = curr + init; + } + else if (s->high_water < (ulg)curr + WIN_INIT) { + /* High water mark at or above current data, but below current data + * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up + * to end of window, whichever is less. + */ + init = (ulg)curr + WIN_INIT - s->high_water; + if (init > s->window_size - s->high_water) + init = s->window_size - s->high_water; + zmemzero(s->window + s->high_water, (unsigned)init); + s->high_water += init; + } + } + + Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, + "not enough room for search"); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, last) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (last)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, last) { \ + FLUSH_BLOCK_ONLY(s, last); \ + if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying from + * window to pending_buf. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + /* Stored blocks are limited to 0xffff bytes, pending_buf is limited + * to pending_buf_size, and each stored block has a 5 byte header: + */ + ulg max_block_size = 0xffff; + ulg max_start; + + if (max_block_size > s->pending_buf_size - 5) { + max_block_size = s->pending_buf_size - 5; + } + + /* Copy as much as possible from input to output: */ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Emit a stored block if pending_buf will be full: */ + max_start = s->block_start + max_block_size; + if (s->strstart == 0 || (ulg)s->strstart >= max_start) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = (uInt)(s->strstart - max_start); + s->strstart = (uInt)max_start; + FLUSH_BLOCK(s, 0); + } + /* Flush if we may have to slide, otherwise block_start may become + * negative and the data will be gone: + */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if ((long)s->strstart > s->block_start) + FLUSH_BLOCK(s, 0); + return block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + _tr_tally_dist(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ +#ifndef FASTEST + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else +#endif + { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; +} + +#ifndef FASTEST +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + hash_head = NIL; + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + s->match_length = longest_match (s, hash_head); + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED +#if TOO_FAR <= 32767 + || (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR) +#endif + )) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + _tr_tally_dist(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH, bflush); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + if (bflush) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally_lit(s, s->window[s->strstart-1], bflush); + s->match_available = 0; + } + s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; +} +#endif /* FASTEST */ + +/* =========================================================================== + * For Z_RLE, simply look for runs of bytes, generate matches only of distance + * one. Do not maintain a hash table. (It will be regenerated if this run of + * deflate switches away from Z_RLE.) + */ +local block_state deflate_rle(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + uInt prev; /* byte at distance one to match */ + Bytef *scan, *strend; /* scan goes up to strend for length of run */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the longest run, plus one for the unrolled loop. + */ + if (s->lookahead <= MAX_MATCH) { + fill_window(s); + if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* See how many times the previous byte repeats */ + s->match_length = 0; + if (s->lookahead >= MIN_MATCH && s->strstart > 0) { + scan = s->window + s->strstart - 1; + prev = *scan; + if (prev == *++scan && prev == *++scan && prev == *++scan) { + strend = s->window + s->strstart + MAX_MATCH; + do { + } while (prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + prev == *++scan && prev == *++scan && + scan < strend); + s->match_length = MAX_MATCH - (int)(strend - scan); + if (s->match_length > s->lookahead) + s->match_length = s->lookahead; + } + Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); + } + + /* Emit match if have run of MIN_MATCH or longer, else emit literal */ + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->strstart - 1, s->match_length); + + _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); + + s->lookahead -= s->match_length; + s->strstart += s->match_length; + s->match_length = 0; + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; +} + +/* =========================================================================== + * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. + * (It will be regenerated if this run of deflate switches away from Huffman.) + */ +local block_state deflate_huff(s, flush) + deflate_state *s; + int flush; +{ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we have a literal to write. */ + if (s->lookahead == 0) { + fill_window(s); + if (s->lookahead == 0) { + if (flush == Z_NO_FLUSH) + return need_more; + break; /* flush the current block */ + } + } + + /* Output a literal byte */ + s->match_length = 0; + Tracevv((stderr,"%c", s->window[s->strstart])); + _tr_tally_lit (s, s->window[s->strstart], bflush); + s->lookahead--; + s->strstart++; + if (bflush) FLUSH_BLOCK(s, 0); + } + s->insert = 0; + if (flush == Z_FINISH) { + FLUSH_BLOCK(s, 1); + return finish_done; + } + if (s->last_lit) + FLUSH_BLOCK(s, 0); + return block_done; +} diff --git a/test/zlib/zlib-1.2.8/deflate.h b/test/zlib/zlib-1.2.8/deflate.h new file mode 100644 index 000000000..ce0299edd --- /dev/null +++ b/test/zlib/zlib-1.2.8/deflate.h @@ -0,0 +1,346 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-2012 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef DEFLATE_H +#define DEFLATE_H + +#include "zutil.h" + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer creation by deflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip encoding + should be left enabled. */ +#ifndef NO_GZIP +# define GZIP +#endif + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define Buf_size 16 +/* size of bit buffer in bi_buf */ + +#define INIT_STATE 42 +#define EXTRA_STATE 69 +#define NAME_STATE 73 +#define COMMENT_STATE 91 +#define HCRC_STATE 103 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + ulg pending_buf_size; /* size of pending_buf */ + Bytef *pending_out; /* next pending byte to output to the stream */ + uInt pending; /* nb of bytes in the pending buffer */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + gz_headerp gzhead; /* gzip header information to write */ + uInt gzindex; /* where in extra, name, or comment */ + Byte method; /* can only be DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to suppress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + uInt matches; /* number of string matches in current block */ + uInt insert; /* bytes at end of window left to insert */ + +#ifdef DEBUG + ulg compressed_len; /* total bit length of compressed file mod 2^32 */ + ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + + ulg high_water; + /* High water mark offset in window for initialized bytes -- bytes above + * this are set to zero in order to avoid memory check warnings when + * longest match routines access bytes past the input. This is then + * updated to the new high water mark. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +#define WIN_INIT MAX_MATCH +/* Number of bytes after end of data in window to initialize in order to avoid + memory checker errors from longest match routines */ + + /* in trees.c */ +void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); +int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); +void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); +void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, + ulg stored_len, int last)); + +#define d_code(dist) \ + ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. _dist_code[256] and _dist_code[257] are never + * used. + */ + +#ifndef DEBUG +/* Inline versions of _tr_tally for speed: */ + +#if defined(GEN_TREES_H) || !defined(STDC) + extern uch ZLIB_INTERNAL _length_code[]; + extern uch ZLIB_INTERNAL _dist_code[]; +#else + extern const uch ZLIB_INTERNAL _length_code[]; + extern const uch ZLIB_INTERNAL _dist_code[]; +#endif + +# define _tr_tally_lit(s, c, flush) \ + { uch cc = (c); \ + s->d_buf[s->last_lit] = 0; \ + s->l_buf[s->last_lit++] = cc; \ + s->dyn_ltree[cc].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +# define _tr_tally_dist(s, distance, length, flush) \ + { uch len = (length); \ + ush dist = (distance); \ + s->d_buf[s->last_lit] = dist; \ + s->l_buf[s->last_lit++] = len; \ + dist--; \ + s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ + s->dyn_dtree[d_code(dist)].Freq++; \ + flush = (s->last_lit == s->lit_bufsize-1); \ + } +#else +# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) +# define _tr_tally_dist(s, distance, length, flush) \ + flush = _tr_tally(s, distance, length) +#endif + +#endif /* DEFLATE_H */ diff --git a/test/zlib/zlib-1.2.8/doc/algorithm.txt b/test/zlib/zlib-1.2.8/doc/algorithm.txt new file mode 100644 index 000000000..c97f49502 --- /dev/null +++ b/test/zlib/zlib-1.2.8/doc/algorithm.txt @@ -0,0 +1,209 @@ +1. Compression algorithm (deflate) + +The deflation algorithm used by gzip (also zip and zlib) is a variation of +LZ77 (Lempel-Ziv 1977, see reference below). It finds duplicated strings in +the input data. The second occurrence of a string is replaced by a +pointer to the previous string, in the form of a pair (distance, +length). Distances are limited to 32K bytes, and lengths are limited +to 258 bytes. When a string does not occur anywhere in the previous +32K bytes, it is emitted as a sequence of literal bytes. (In this +description, `string' must be taken as an arbitrary sequence of bytes, +and is not restricted to printable characters.) + +Literals or match lengths are compressed with one Huffman tree, and +match distances are compressed with another tree. The trees are stored +in a compact form at the start of each block. The blocks can have any +size (except that the compressed data for one block must fit in +available memory). A block is terminated when deflate() determines that +it would be useful to start another block with fresh trees. (This is +somewhat similar to the behavior of LZW-based _compress_.) + +Duplicated strings are found using a hash table. All input strings of +length 3 are inserted in the hash table. A hash index is computed for +the next 3 bytes. If the hash chain for this index is not empty, all +strings in the chain are compared with the current input string, and +the longest match is selected. + +The hash chains are searched starting with the most recent strings, to +favor small distances and thus take advantage of the Huffman encoding. +The hash chains are singly linked. There are no deletions from the +hash chains, the algorithm simply discards matches that are too old. + +To avoid a worst-case situation, very long hash chains are arbitrarily +truncated at a certain length, determined by a runtime option (level +parameter of deflateInit). So deflate() does not always find the longest +possible match but generally finds a match which is long enough. + +deflate() also defers the selection of matches with a lazy evaluation +mechanism. After a match of length N has been found, deflate() searches for +a longer match at the next input byte. If a longer match is found, the +previous match is truncated to a length of one (thus producing a single +literal byte) and the process of lazy evaluation begins again. Otherwise, +the original match is kept, and the next match search is attempted only N +steps later. + +The lazy match evaluation is also subject to a runtime parameter. If +the current match is long enough, deflate() reduces the search for a longer +match, thus speeding up the whole process. If compression ratio is more +important than speed, deflate() attempts a complete second search even if +the first match is already long enough. + +The lazy match evaluation is not performed for the fastest compression +modes (level parameter 1 to 3). For these fast modes, new strings +are inserted in the hash table only when no match was found, or +when the match is not too long. This degrades the compression ratio +but saves time since there are both fewer insertions and fewer searches. + + +2. Decompression algorithm (inflate) + +2.1 Introduction + +The key question is how to represent a Huffman code (or any prefix code) so +that you can decode fast. The most important characteristic is that shorter +codes are much more common than longer codes, so pay attention to decoding the +short codes fast, and let the long codes take longer to decode. + +inflate() sets up a first level table that covers some number of bits of +input less than the length of longest code. It gets that many bits from the +stream, and looks it up in the table. The table will tell if the next +code is that many bits or less and how many, and if it is, it will tell +the value, else it will point to the next level table for which inflate() +grabs more bits and tries to decode a longer code. + +How many bits to make the first lookup is a tradeoff between the time it +takes to decode and the time it takes to build the table. If building the +table took no time (and if you had infinite memory), then there would only +be a first level table to cover all the way to the longest code. However, +building the table ends up taking a lot longer for more bits since short +codes are replicated many times in such a table. What inflate() does is +simply to make the number of bits in the first table a variable, and then +to set that variable for the maximum speed. + +For inflate, which has 286 possible codes for the literal/length tree, the size +of the first table is nine bits. Also the distance trees have 30 possible +values, and the size of the first table is six bits. Note that for each of +those cases, the table ended up one bit longer than the ``average'' code +length, i.e. the code length of an approximately flat code which would be a +little more than eight bits for 286 symbols and a little less than five bits +for 30 symbols. + + +2.2 More details on the inflate table lookup + +Ok, you want to know what this cleverly obfuscated inflate tree actually +looks like. You are correct that it's not a Huffman tree. It is simply a +lookup table for the first, let's say, nine bits of a Huffman symbol. The +symbol could be as short as one bit or as long as 15 bits. If a particular +symbol is shorter than nine bits, then that symbol's translation is duplicated +in all those entries that start with that symbol's bits. For example, if the +symbol is four bits, then it's duplicated 32 times in a nine-bit table. If a +symbol is nine bits long, it appears in the table once. + +If the symbol is longer than nine bits, then that entry in the table points +to another similar table for the remaining bits. Again, there are duplicated +entries as needed. The idea is that most of the time the symbol will be short +and there will only be one table look up. (That's whole idea behind data +compression in the first place.) For the less frequent long symbols, there +will be two lookups. If you had a compression method with really long +symbols, you could have as many levels of lookups as is efficient. For +inflate, two is enough. + +So a table entry either points to another table (in which case nine bits in +the above example are gobbled), or it contains the translation for the symbol +and the number of bits to gobble. Then you start again with the next +ungobbled bit. + +You may wonder: why not just have one lookup table for how ever many bits the +longest symbol is? The reason is that if you do that, you end up spending +more time filling in duplicate symbol entries than you do actually decoding. +At least for deflate's output that generates new trees every several 10's of +kbytes. You can imagine that filling in a 2^15 entry table for a 15-bit code +would take too long if you're only decoding several thousand symbols. At the +other extreme, you could make a new table for every bit in the code. In fact, +that's essentially a Huffman tree. But then you spend too much time +traversing the tree while decoding, even for short symbols. + +So the number of bits for the first lookup table is a trade of the time to +fill out the table vs. the time spent looking at the second level and above of +the table. + +Here is an example, scaled down: + +The code being decoded, with 10 symbols, from 1 to 6 bits long: + +A: 0 +B: 10 +C: 1100 +D: 11010 +E: 11011 +F: 11100 +G: 11101 +H: 11110 +I: 111110 +J: 111111 + +Let's make the first table three bits long (eight entries): + +000: A,1 +001: A,1 +010: A,1 +011: A,1 +100: B,2 +101: B,2 +110: -> table X (gobble 3 bits) +111: -> table Y (gobble 3 bits) + +Each entry is what the bits decode as and how many bits that is, i.e. how +many bits to gobble. Or the entry points to another table, with the number of +bits to gobble implicit in the size of the table. + +Table X is two bits long since the longest code starting with 110 is five bits +long: + +00: C,1 +01: C,1 +10: D,2 +11: E,2 + +Table Y is three bits long since the longest code starting with 111 is six +bits long: + +000: F,2 +001: F,2 +010: G,2 +011: G,2 +100: H,2 +101: H,2 +110: I,3 +111: J,3 + +So what we have here are three tables with a total of 20 entries that had to +be constructed. That's compared to 64 entries for a single table. Or +compared to 16 entries for a Huffman tree (six two entry tables and one four +entry table). Assuming that the code ideally represents the probability of +the symbols, it takes on the average 1.25 lookups per symbol. That's compared +to one lookup for the single table, or 1.66 lookups per symbol for the +Huffman tree. + +There, I think that gives you a picture of what's going on. For inflate, the +meaning of a particular symbol is often more than just a letter. It can be a +byte (a "literal"), or it can be either a length or a distance which +indicates a base value and a number of bits to fetch after the code that is +added to the base value. Or it might be the special end-of-block code. The +data structures created in inftrees.c try to encode all that information +compactly in the tables. + + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu + + +References: + +[LZ77] Ziv J., Lempel A., ``A Universal Algorithm for Sequential Data +Compression,'' IEEE Transactions on Information Theory, Vol. 23, No. 3, +pp. 337-343. + +``DEFLATE Compressed Data Format Specification'' available in +http://tools.ietf.org/html/rfc1951 diff --git a/test/zlib/zlib-1.2.8/doc/rfc1950.txt b/test/zlib/zlib-1.2.8/doc/rfc1950.txt new file mode 100644 index 000000000..ce6428a0f --- /dev/null +++ b/test/zlib/zlib-1.2.8/doc/rfc1950.txt @@ -0,0 +1,619 @@ + + + + + + +Network Working Group P. Deutsch +Request for Comments: 1950 Aladdin Enterprises +Category: Informational J-L. Gailly + Info-ZIP + May 1996 + + + ZLIB Compressed Data Format Specification version 3.3 + +Status of This Memo + + This memo provides information for the Internet community. This memo + does not specify an Internet standard of any kind. Distribution of + this memo is unlimited. + +IESG Note: + + The IESG takes no position on the validity of any Intellectual + Property Rights statements contained in this document. + +Notices + + Copyright (c) 1996 L. Peter Deutsch and Jean-Loup Gailly + + Permission is granted to copy and distribute this document for any + purpose and without charge, including translations into other + languages and incorporation into compilations, provided that the + copyright notice and this notice are preserved, and that any + substantive changes or deletions from the original are clearly + marked. + + A pointer to the latest version of this and related documentation in + HTML format can be found at the URL + . + +Abstract + + This specification defines a lossless compressed data format. The + data can be produced or consumed, even for an arbitrarily long + sequentially presented input data stream, using only an a priori + bounded amount of intermediate storage. The format presently uses + the DEFLATE compression method but can be easily extended to use + other compression methods. It can be implemented readily in a manner + not covered by patents. This specification also defines the ADLER-32 + checksum (an extension and improvement of the Fletcher checksum), + used for detection of data corruption, and provides an algorithm for + computing it. + + + + +Deutsch & Gailly Informational [Page 1] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +Table of Contents + + 1. Introduction ................................................... 2 + 1.1. Purpose ................................................... 2 + 1.2. Intended audience ......................................... 3 + 1.3. Scope ..................................................... 3 + 1.4. Compliance ................................................ 3 + 1.5. Definitions of terms and conventions used ................ 3 + 1.6. Changes from previous versions ............................ 3 + 2. Detailed specification ......................................... 3 + 2.1. Overall conventions ....................................... 3 + 2.2. Data format ............................................... 4 + 2.3. Compliance ................................................ 7 + 3. References ..................................................... 7 + 4. Source code .................................................... 8 + 5. Security Considerations ........................................ 8 + 6. Acknowledgements ............................................... 8 + 7. Authors' Addresses ............................................. 8 + 8. Appendix: Rationale ............................................ 9 + 9. Appendix: Sample code ..........................................10 + +1. Introduction + + 1.1. Purpose + + The purpose of this specification is to define a lossless + compressed data format that: + + * Is independent of CPU type, operating system, file system, + and character set, and hence can be used for interchange; + + * Can be produced or consumed, even for an arbitrarily long + sequentially presented input data stream, using only an a + priori bounded amount of intermediate storage, and hence can + be used in data communications or similar structures such as + Unix filters; + + * Can use a number of different compression methods; + + * Can be implemented readily in a manner not covered by + patents, and hence can be practiced freely. + + The data format defined by this specification does not attempt to + allow random access to compressed data. + + + + + + + +Deutsch & Gailly Informational [Page 2] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + 1.2. Intended audience + + This specification is intended for use by implementors of software + to compress data into zlib format and/or decompress data from zlib + format. + + The text of the specification assumes a basic background in + programming at the level of bits and other primitive data + representations. + + 1.3. Scope + + The specification specifies a compressed data format that can be + used for in-memory compression of a sequence of arbitrary bytes. + + 1.4. Compliance + + Unless otherwise indicated below, a compliant decompressor must be + able to accept and decompress any data set that conforms to all + the specifications presented here; a compliant compressor must + produce data sets that conform to all the specifications presented + here. + + 1.5. Definitions of terms and conventions used + + byte: 8 bits stored or transmitted as a unit (same as an octet). + (For this specification, a byte is exactly 8 bits, even on + machines which store a character on a number of bits different + from 8.) See below, for the numbering of bits within a byte. + + 1.6. Changes from previous versions + + Version 3.1 was the first public release of this specification. + In version 3.2, some terminology was changed and the Adler-32 + sample code was rewritten for clarity. In version 3.3, the + support for a preset dictionary was introduced, and the + specification was converted to RFC style. + +2. Detailed specification + + 2.1. Overall conventions + + In the diagrams below, a box like this: + + +---+ + | | <-- the vertical bars might be missing + +---+ + + + + +Deutsch & Gailly Informational [Page 3] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + represents one byte; a box like this: + + +==============+ + | | + +==============+ + + represents a variable number of bytes. + + Bytes stored within a computer do not have a "bit order", since + they are always treated as a unit. However, a byte considered as + an integer between 0 and 255 does have a most- and least- + significant bit, and since we write numbers with the most- + significant digit on the left, we also write bytes with the most- + significant bit on the left. In the diagrams below, we number the + bits of a byte so that bit 0 is the least-significant bit, i.e., + the bits are numbered: + + +--------+ + |76543210| + +--------+ + + Within a computer, a number may occupy multiple bytes. All + multi-byte numbers in the format described here are stored with + the MOST-significant byte first (at the lower memory address). + For example, the decimal number 520 is stored as: + + 0 1 + +--------+--------+ + |00000010|00001000| + +--------+--------+ + ^ ^ + | | + | + less significant byte = 8 + + more significant byte = 2 x 256 + + 2.2. Data format + + A zlib stream has the following structure: + + 0 1 + +---+---+ + |CMF|FLG| (more-->) + +---+---+ + + + + + + + + +Deutsch & Gailly Informational [Page 4] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + (if FLG.FDICT set) + + 0 1 2 3 + +---+---+---+---+ + | DICTID | (more-->) + +---+---+---+---+ + + +=====================+---+---+---+---+ + |...compressed data...| ADLER32 | + +=====================+---+---+---+---+ + + Any data which may appear after ADLER32 are not part of the zlib + stream. + + CMF (Compression Method and flags) + This byte is divided into a 4-bit compression method and a 4- + bit information field depending on the compression method. + + bits 0 to 3 CM Compression method + bits 4 to 7 CINFO Compression info + + CM (Compression method) + This identifies the compression method used in the file. CM = 8 + denotes the "deflate" compression method with a window size up + to 32K. This is the method used by gzip and PNG (see + references [1] and [2] in Chapter 3, below, for the reference + documents). CM = 15 is reserved. It might be used in a future + version of this specification to indicate the presence of an + extra field before the compressed data. + + CINFO (Compression info) + For CM = 8, CINFO is the base-2 logarithm of the LZ77 window + size, minus eight (CINFO=7 indicates a 32K window size). Values + of CINFO above 7 are not allowed in this version of the + specification. CINFO is not defined in this specification for + CM not equal to 8. + + FLG (FLaGs) + This flag byte is divided as follows: + + bits 0 to 4 FCHECK (check bits for CMF and FLG) + bit 5 FDICT (preset dictionary) + bits 6 to 7 FLEVEL (compression level) + + The FCHECK value must be such that CMF and FLG, when viewed as + a 16-bit unsigned integer stored in MSB order (CMF*256 + FLG), + is a multiple of 31. + + + + +Deutsch & Gailly Informational [Page 5] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + FDICT (Preset dictionary) + If FDICT is set, a DICT dictionary identifier is present + immediately after the FLG byte. The dictionary is a sequence of + bytes which are initially fed to the compressor without + producing any compressed output. DICT is the Adler-32 checksum + of this sequence of bytes (see the definition of ADLER32 + below). The decompressor can use this identifier to determine + which dictionary has been used by the compressor. + + FLEVEL (Compression level) + These flags are available for use by specific compression + methods. The "deflate" method (CM = 8) sets these flags as + follows: + + 0 - compressor used fastest algorithm + 1 - compressor used fast algorithm + 2 - compressor used default algorithm + 3 - compressor used maximum compression, slowest algorithm + + The information in FLEVEL is not needed for decompression; it + is there to indicate if recompression might be worthwhile. + + compressed data + For compression method 8, the compressed data is stored in the + deflate compressed data format as described in the document + "DEFLATE Compressed Data Format Specification" by L. Peter + Deutsch. (See reference [3] in Chapter 3, below) + + Other compressed data formats are not specified in this version + of the zlib specification. + + ADLER32 (Adler-32 checksum) + This contains a checksum value of the uncompressed data + (excluding any dictionary data) computed according to Adler-32 + algorithm. This algorithm is a 32-bit extension and improvement + of the Fletcher algorithm, used in the ITU-T X.224 / ISO 8073 + standard. See references [4] and [5] in Chapter 3, below) + + Adler-32 is composed of two sums accumulated per byte: s1 is + the sum of all bytes, s2 is the sum of all s1 values. Both sums + are done modulo 65521. s1 is initialized to 1, s2 to zero. The + Adler-32 checksum is stored as s2*65536 + s1 in most- + significant-byte first (network) order. + + + + + + + + +Deutsch & Gailly Informational [Page 6] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + 2.3. Compliance + + A compliant compressor must produce streams with correct CMF, FLG + and ADLER32, but need not support preset dictionaries. When the + zlib data format is used as part of another standard data format, + the compressor may use only preset dictionaries that are specified + by this other data format. If this other format does not use the + preset dictionary feature, the compressor must not set the FDICT + flag. + + A compliant decompressor must check CMF, FLG, and ADLER32, and + provide an error indication if any of these have incorrect values. + A compliant decompressor must give an error indication if CM is + not one of the values defined in this specification (only the + value 8 is permitted in this version), since another value could + indicate the presence of new features that would cause subsequent + data to be interpreted incorrectly. A compliant decompressor must + give an error indication if FDICT is set and DICTID is not the + identifier of a known preset dictionary. A decompressor may + ignore FLEVEL and still be compliant. When the zlib data format + is being used as a part of another standard format, a compliant + decompressor must support all the preset dictionaries specified by + the other format. When the other format does not use the preset + dictionary feature, a compliant decompressor must reject any + stream in which the FDICT flag is set. + +3. References + + [1] Deutsch, L.P.,"GZIP Compressed Data Format Specification", + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [2] Thomas Boutell, "PNG (Portable Network Graphics) specification", + available in ftp://ftp.uu.net/graphics/png/documents/ + + [3] Deutsch, L.P.,"DEFLATE Compressed Data Format Specification", + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [4] Fletcher, J. G., "An Arithmetic Checksum for Serial + Transmissions," IEEE Transactions on Communications, Vol. COM-30, + No. 1, January 1982, pp. 247-252. + + [5] ITU-T Recommendation X.224, Annex D, "Checksum Algorithms," + November, 1993, pp. 144, 145. (Available from + gopher://info.itu.ch). ITU-T X.244 is also the same as ISO 8073. + + + + + + + +Deutsch & Gailly Informational [Page 7] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +4. Source code + + Source code for a C language implementation of a "zlib" compliant + library is available at ftp://ftp.uu.net/pub/archiving/zip/zlib/. + +5. Security Considerations + + A decoder that fails to check the ADLER32 checksum value may be + subject to undetected data corruption. + +6. Acknowledgements + + Trademarks cited in this document are the property of their + respective owners. + + Jean-Loup Gailly and Mark Adler designed the zlib format and wrote + the related software described in this specification. Glenn + Randers-Pehrson converted this document to RFC and HTML format. + +7. Authors' Addresses + + L. Peter Deutsch + Aladdin Enterprises + 203 Santa Margarita Ave. + Menlo Park, CA 94025 + + Phone: (415) 322-0103 (AM only) + FAX: (415) 322-1734 + EMail: + + + Jean-Loup Gailly + + EMail: + + Questions about the technical content of this specification can be + sent by email to + + Jean-Loup Gailly and + Mark Adler + + Editorial comments on this specification can be sent by email to + + L. Peter Deutsch and + Glenn Randers-Pehrson + + + + + + +Deutsch & Gailly Informational [Page 8] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +8. Appendix: Rationale + + 8.1. Preset dictionaries + + A preset dictionary is specially useful to compress short input + sequences. The compressor can take advantage of the dictionary + context to encode the input in a more compact manner. The + decompressor can be initialized with the appropriate context by + virtually decompressing a compressed version of the dictionary + without producing any output. However for certain compression + algorithms such as the deflate algorithm this operation can be + achieved without actually performing any decompression. + + The compressor and the decompressor must use exactly the same + dictionary. The dictionary may be fixed or may be chosen among a + certain number of predefined dictionaries, according to the kind + of input data. The decompressor can determine which dictionary has + been chosen by the compressor by checking the dictionary + identifier. This document does not specify the contents of + predefined dictionaries, since the optimal dictionaries are + application specific. Standard data formats using this feature of + the zlib specification must precisely define the allowed + dictionaries. + + 8.2. The Adler-32 algorithm + + The Adler-32 algorithm is much faster than the CRC32 algorithm yet + still provides an extremely low probability of undetected errors. + + The modulo on unsigned long accumulators can be delayed for 5552 + bytes, so the modulo operation time is negligible. If the bytes + are a, b, c, the second sum is 3a + 2b + c + 3, and so is position + and order sensitive, unlike the first sum, which is just a + checksum. That 65521 is prime is important to avoid a possible + large class of two-byte errors that leave the check unchanged. + (The Fletcher checksum uses 255, which is not prime and which also + makes the Fletcher check insensitive to single byte changes 0 <-> + 255.) + + The sum s1 is initialized to 1 instead of zero to make the length + of the sequence part of s2, so that the length does not have to be + checked separately. (Any sequence of zeroes has a Fletcher + checksum of zero.) + + + + + + + + +Deutsch & Gailly Informational [Page 9] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + +9. Appendix: Sample code + + The following C code computes the Adler-32 checksum of a data buffer. + It is written for clarity, not for speed. The sample code is in the + ANSI C programming language. Non C users may find it easier to read + with these hints: + + & Bitwise AND operator. + >> Bitwise right shift operator. When applied to an + unsigned quantity, as here, right shift inserts zero bit(s) + at the left. + << Bitwise left shift operator. Left shift inserts zero + bit(s) at the right. + ++ "n++" increments the variable n. + % modulo operator: a % b is the remainder of a divided by b. + + #define BASE 65521 /* largest prime smaller than 65536 */ + + /* + Update a running Adler-32 checksum with the bytes buf[0..len-1] + and return the updated checksum. The Adler-32 checksum should be + initialized to 1. + + Usage example: + + unsigned long adler = 1L; + + while (read_buffer(buffer, length) != EOF) { + adler = update_adler32(adler, buffer, length); + } + if (adler != original_adler) error(); + */ + unsigned long update_adler32(unsigned long adler, + unsigned char *buf, int len) + { + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int n; + + for (n = 0; n < len; n++) { + s1 = (s1 + buf[n]) % BASE; + s2 = (s2 + s1) % BASE; + } + return (s2 << 16) + s1; + } + + /* Return the adler32 of the bytes buf[0..len-1] */ + + + + +Deutsch & Gailly Informational [Page 10] + +RFC 1950 ZLIB Compressed Data Format Specification May 1996 + + + unsigned long adler32(unsigned char *buf, int len) + { + return update_adler32(1L, buf, len); + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Deutsch & Gailly Informational [Page 11] + diff --git a/test/zlib/zlib-1.2.8/doc/rfc1951.txt b/test/zlib/zlib-1.2.8/doc/rfc1951.txt new file mode 100644 index 000000000..403c8c722 --- /dev/null +++ b/test/zlib/zlib-1.2.8/doc/rfc1951.txt @@ -0,0 +1,955 @@ + + + + + + +Network Working Group P. Deutsch +Request for Comments: 1951 Aladdin Enterprises +Category: Informational May 1996 + + + DEFLATE Compressed Data Format Specification version 1.3 + +Status of This Memo + + This memo provides information for the Internet community. This memo + does not specify an Internet standard of any kind. Distribution of + this memo is unlimited. + +IESG Note: + + The IESG takes no position on the validity of any Intellectual + Property Rights statements contained in this document. + +Notices + + Copyright (c) 1996 L. Peter Deutsch + + Permission is granted to copy and distribute this document for any + purpose and without charge, including translations into other + languages and incorporation into compilations, provided that the + copyright notice and this notice are preserved, and that any + substantive changes or deletions from the original are clearly + marked. + + A pointer to the latest version of this and related documentation in + HTML format can be found at the URL + . + +Abstract + + This specification defines a lossless compressed data format that + compresses data using a combination of the LZ77 algorithm and Huffman + coding, with efficiency comparable to the best currently available + general-purpose compression methods. The data can be produced or + consumed, even for an arbitrarily long sequentially presented input + data stream, using only an a priori bounded amount of intermediate + storage. The format can be implemented readily in a manner not + covered by patents. + + + + + + + + +Deutsch Informational [Page 1] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +Table of Contents + + 1. Introduction ................................................... 2 + 1.1. Purpose ................................................... 2 + 1.2. Intended audience ......................................... 3 + 1.3. Scope ..................................................... 3 + 1.4. Compliance ................................................ 3 + 1.5. Definitions of terms and conventions used ................ 3 + 1.6. Changes from previous versions ............................ 4 + 2. Compressed representation overview ............................. 4 + 3. Detailed specification ......................................... 5 + 3.1. Overall conventions ....................................... 5 + 3.1.1. Packing into bytes .................................. 5 + 3.2. Compressed block format ................................... 6 + 3.2.1. Synopsis of prefix and Huffman coding ............... 6 + 3.2.2. Use of Huffman coding in the "deflate" format ....... 7 + 3.2.3. Details of block format ............................. 9 + 3.2.4. Non-compressed blocks (BTYPE=00) ................... 11 + 3.2.5. Compressed blocks (length and distance codes) ...... 11 + 3.2.6. Compression with fixed Huffman codes (BTYPE=01) .... 12 + 3.2.7. Compression with dynamic Huffman codes (BTYPE=10) .. 13 + 3.3. Compliance ............................................... 14 + 4. Compression algorithm details ................................. 14 + 5. References .................................................... 16 + 6. Security Considerations ....................................... 16 + 7. Source code ................................................... 16 + 8. Acknowledgements .............................................. 16 + 9. Author's Address .............................................. 17 + +1. Introduction + + 1.1. Purpose + + The purpose of this specification is to define a lossless + compressed data format that: + * Is independent of CPU type, operating system, file system, + and character set, and hence can be used for interchange; + * Can be produced or consumed, even for an arbitrarily long + sequentially presented input data stream, using only an a + priori bounded amount of intermediate storage, and hence + can be used in data communications or similar structures + such as Unix filters; + * Compresses data with efficiency comparable to the best + currently available general-purpose compression methods, + and in particular considerably better than the "compress" + program; + * Can be implemented readily in a manner not covered by + patents, and hence can be practiced freely; + + + +Deutsch Informational [Page 2] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + * Is compatible with the file format produced by the current + widely used gzip utility, in that conforming decompressors + will be able to read data produced by the existing gzip + compressor. + + The data format defined by this specification does not attempt to: + + * Allow random access to compressed data; + * Compress specialized data (e.g., raster graphics) as well + as the best currently available specialized algorithms. + + A simple counting argument shows that no lossless compression + algorithm can compress every possible input data set. For the + format defined here, the worst case expansion is 5 bytes per 32K- + byte block, i.e., a size increase of 0.015% for large data sets. + English text usually compresses by a factor of 2.5 to 3; + executable files usually compress somewhat less; graphical data + such as raster images may compress much more. + + 1.2. Intended audience + + This specification is intended for use by implementors of software + to compress data into "deflate" format and/or decompress data from + "deflate" format. + + The text of the specification assumes a basic background in + programming at the level of bits and other primitive data + representations. Familiarity with the technique of Huffman coding + is helpful but not required. + + 1.3. Scope + + The specification specifies a method for representing a sequence + of bytes as a (usually shorter) sequence of bits, and a method for + packing the latter bit sequence into bytes. + + 1.4. Compliance + + Unless otherwise indicated below, a compliant decompressor must be + able to accept and decompress any data set that conforms to all + the specifications presented here; a compliant compressor must + produce data sets that conform to all the specifications presented + here. + + 1.5. Definitions of terms and conventions used + + Byte: 8 bits stored or transmitted as a unit (same as an octet). + For this specification, a byte is exactly 8 bits, even on machines + + + +Deutsch Informational [Page 3] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + which store a character on a number of bits different from eight. + See below, for the numbering of bits within a byte. + + String: a sequence of arbitrary bytes. + + 1.6. Changes from previous versions + + There have been no technical changes to the deflate format since + version 1.1 of this specification. In version 1.2, some + terminology was changed. Version 1.3 is a conversion of the + specification to RFC style. + +2. Compressed representation overview + + A compressed data set consists of a series of blocks, corresponding + to successive blocks of input data. The block sizes are arbitrary, + except that non-compressible blocks are limited to 65,535 bytes. + + Each block is compressed using a combination of the LZ77 algorithm + and Huffman coding. The Huffman trees for each block are independent + of those for previous or subsequent blocks; the LZ77 algorithm may + use a reference to a duplicated string occurring in a previous block, + up to 32K input bytes before. + + Each block consists of two parts: a pair of Huffman code trees that + describe the representation of the compressed data part, and a + compressed data part. (The Huffman trees themselves are compressed + using Huffman encoding.) The compressed data consists of a series of + elements of two types: literal bytes (of strings that have not been + detected as duplicated within the previous 32K input bytes), and + pointers to duplicated strings, where a pointer is represented as a + pair . The representation used in the + "deflate" format limits distances to 32K bytes and lengths to 258 + bytes, but does not limit the size of a block, except for + uncompressible blocks, which are limited as noted above. + + Each type of value (literals, distances, and lengths) in the + compressed data is represented using a Huffman code, using one code + tree for literals and lengths and a separate code tree for distances. + The code trees for each block appear in a compact form just before + the compressed data for that block. + + + + + + + + + + +Deutsch Informational [Page 4] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +3. Detailed specification + + 3.1. Overall conventions In the diagrams below, a box like this: + + +---+ + | | <-- the vertical bars might be missing + +---+ + + represents one byte; a box like this: + + +==============+ + | | + +==============+ + + represents a variable number of bytes. + + Bytes stored within a computer do not have a "bit order", since + they are always treated as a unit. However, a byte considered as + an integer between 0 and 255 does have a most- and least- + significant bit, and since we write numbers with the most- + significant digit on the left, we also write bytes with the most- + significant bit on the left. In the diagrams below, we number the + bits of a byte so that bit 0 is the least-significant bit, i.e., + the bits are numbered: + + +--------+ + |76543210| + +--------+ + + Within a computer, a number may occupy multiple bytes. All + multi-byte numbers in the format described here are stored with + the least-significant byte first (at the lower memory address). + For example, the decimal number 520 is stored as: + + 0 1 + +--------+--------+ + |00001000|00000010| + +--------+--------+ + ^ ^ + | | + | + more significant byte = 2 x 256 + + less significant byte = 8 + + 3.1.1. Packing into bytes + + This document does not address the issue of the order in which + bits of a byte are transmitted on a bit-sequential medium, + since the final data format described here is byte- rather than + + + +Deutsch Informational [Page 5] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + bit-oriented. However, we describe the compressed block format + in below, as a sequence of data elements of various bit + lengths, not a sequence of bytes. We must therefore specify + how to pack these data elements into bytes to form the final + compressed byte sequence: + + * Data elements are packed into bytes in order of + increasing bit number within the byte, i.e., starting + with the least-significant bit of the byte. + * Data elements other than Huffman codes are packed + starting with the least-significant bit of the data + element. + * Huffman codes are packed starting with the most- + significant bit of the code. + + In other words, if one were to print out the compressed data as + a sequence of bytes, starting with the first byte at the + *right* margin and proceeding to the *left*, with the most- + significant bit of each byte on the left as usual, one would be + able to parse the result from right to left, with fixed-width + elements in the correct MSB-to-LSB order and Huffman codes in + bit-reversed order (i.e., with the first bit of the code in the + relative LSB position). + + 3.2. Compressed block format + + 3.2.1. Synopsis of prefix and Huffman coding + + Prefix coding represents symbols from an a priori known + alphabet by bit sequences (codes), one code for each symbol, in + a manner such that different symbols may be represented by bit + sequences of different lengths, but a parser can always parse + an encoded string unambiguously symbol-by-symbol. + + We define a prefix code in terms of a binary tree in which the + two edges descending from each non-leaf node are labeled 0 and + 1 and in which the leaf nodes correspond one-for-one with (are + labeled with) the symbols of the alphabet; then the code for a + symbol is the sequence of 0's and 1's on the edges leading from + the root to the leaf labeled with that symbol. For example: + + + + + + + + + + + +Deutsch Informational [Page 6] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + /\ Symbol Code + 0 1 ------ ---- + / \ A 00 + /\ B B 1 + 0 1 C 011 + / \ D 010 + A /\ + 0 1 + / \ + D C + + A parser can decode the next symbol from an encoded input + stream by walking down the tree from the root, at each step + choosing the edge corresponding to the next input bit. + + Given an alphabet with known symbol frequencies, the Huffman + algorithm allows the construction of an optimal prefix code + (one which represents strings with those symbol frequencies + using the fewest bits of any possible prefix codes for that + alphabet). Such a code is called a Huffman code. (See + reference [1] in Chapter 5, references for additional + information on Huffman codes.) + + Note that in the "deflate" format, the Huffman codes for the + various alphabets must not exceed certain maximum code lengths. + This constraint complicates the algorithm for computing code + lengths from symbol frequencies. Again, see Chapter 5, + references for details. + + 3.2.2. Use of Huffman coding in the "deflate" format + + The Huffman codes used for each alphabet in the "deflate" + format have two additional rules: + + * All codes of a given bit length have lexicographically + consecutive values, in the same order as the symbols + they represent; + + * Shorter codes lexicographically precede longer codes. + + + + + + + + + + + + +Deutsch Informational [Page 7] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + We could recode the example above to follow this rule as + follows, assuming that the order of the alphabet is ABCD: + + Symbol Code + ------ ---- + A 10 + B 0 + C 110 + D 111 + + I.e., 0 precedes 10 which precedes 11x, and 110 and 111 are + lexicographically consecutive. + + Given this rule, we can define the Huffman code for an alphabet + just by giving the bit lengths of the codes for each symbol of + the alphabet in order; this is sufficient to determine the + actual codes. In our example, the code is completely defined + by the sequence of bit lengths (2, 1, 3, 3). The following + algorithm generates the codes as integers, intended to be read + from most- to least-significant bit. The code lengths are + initially in tree[I].Len; the codes are produced in + tree[I].Code. + + 1) Count the number of codes for each code length. Let + bl_count[N] be the number of codes of length N, N >= 1. + + 2) Find the numerical value of the smallest code for each + code length: + + code = 0; + bl_count[0] = 0; + for (bits = 1; bits <= MAX_BITS; bits++) { + code = (code + bl_count[bits-1]) << 1; + next_code[bits] = code; + } + + 3) Assign numerical values to all codes, using consecutive + values for all codes of the same length with the base + values determined at step 2. Codes that are never used + (which have a bit length of zero) must not be assigned a + value. + + for (n = 0; n <= max_code; n++) { + len = tree[n].Len; + if (len != 0) { + tree[n].Code = next_code[len]; + next_code[len]++; + } + + + +Deutsch Informational [Page 8] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + } + + Example: + + Consider the alphabet ABCDEFGH, with bit lengths (3, 3, 3, 3, + 3, 2, 4, 4). After step 1, we have: + + N bl_count[N] + - ----------- + 2 1 + 3 5 + 4 2 + + Step 2 computes the following next_code values: + + N next_code[N] + - ------------ + 1 0 + 2 0 + 3 2 + 4 14 + + Step 3 produces the following code values: + + Symbol Length Code + ------ ------ ---- + A 3 010 + B 3 011 + C 3 100 + D 3 101 + E 3 110 + F 2 00 + G 4 1110 + H 4 1111 + + 3.2.3. Details of block format + + Each block of compressed data begins with 3 header bits + containing the following data: + + first bit BFINAL + next 2 bits BTYPE + + Note that the header bits do not necessarily begin on a byte + boundary, since a block does not necessarily occupy an integral + number of bytes. + + + + + +Deutsch Informational [Page 9] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + BFINAL is set if and only if this is the last block of the data + set. + + BTYPE specifies how the data are compressed, as follows: + + 00 - no compression + 01 - compressed with fixed Huffman codes + 10 - compressed with dynamic Huffman codes + 11 - reserved (error) + + The only difference between the two compressed cases is how the + Huffman codes for the literal/length and distance alphabets are + defined. + + In all cases, the decoding algorithm for the actual data is as + follows: + + do + read block header from input stream. + if stored with no compression + skip any remaining bits in current partially + processed byte + read LEN and NLEN (see next section) + copy LEN bytes of data to output + otherwise + if compressed with dynamic Huffman codes + read representation of code trees (see + subsection below) + loop (until end of block code recognized) + decode literal/length value from input stream + if value < 256 + copy value (literal byte) to output stream + otherwise + if value = end of block (256) + break from loop + otherwise (value = 257..285) + decode distance from input stream + + move backwards distance bytes in the output + stream, and copy length bytes from this + position to the output stream. + end loop + while not last block + + Note that a duplicated string reference may refer to a string + in a previous block; i.e., the backward distance may cross one + or more block boundaries. However a distance cannot refer past + the beginning of the output stream. (An application using a + + + +Deutsch Informational [Page 10] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + preset dictionary might discard part of the output stream; a + distance can refer to that part of the output stream anyway) + Note also that the referenced string may overlap the current + position; for example, if the last 2 bytes decoded have values + X and Y, a string reference with + adds X,Y,X,Y,X to the output stream. + + We now specify each compression method in turn. + + 3.2.4. Non-compressed blocks (BTYPE=00) + + Any bits of input up to the next byte boundary are ignored. + The rest of the block consists of the following information: + + 0 1 2 3 4... + +---+---+---+---+================================+ + | LEN | NLEN |... LEN bytes of literal data...| + +---+---+---+---+================================+ + + LEN is the number of data bytes in the block. NLEN is the + one's complement of LEN. + + 3.2.5. Compressed blocks (length and distance codes) + + As noted above, encoded data blocks in the "deflate" format + consist of sequences of symbols drawn from three conceptually + distinct alphabets: either literal bytes, from the alphabet of + byte values (0..255), or pairs, + where the length is drawn from (3..258) and the distance is + drawn from (1..32,768). In fact, the literal and length + alphabets are merged into a single alphabet (0..285), where + values 0..255 represent literal bytes, the value 256 indicates + end-of-block, and values 257..285 represent length codes + (possibly in conjunction with extra bits following the symbol + code) as follows: + + + + + + + + + + + + + + + + +Deutsch Informational [Page 11] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + Extra Extra Extra + Code Bits Length(s) Code Bits Lengths Code Bits Length(s) + ---- ---- ------ ---- ---- ------- ---- ---- ------- + 257 0 3 267 1 15,16 277 4 67-82 + 258 0 4 268 1 17,18 278 4 83-98 + 259 0 5 269 2 19-22 279 4 99-114 + 260 0 6 270 2 23-26 280 4 115-130 + 261 0 7 271 2 27-30 281 5 131-162 + 262 0 8 272 2 31-34 282 5 163-194 + 263 0 9 273 3 35-42 283 5 195-226 + 264 0 10 274 3 43-50 284 5 227-257 + 265 1 11,12 275 3 51-58 285 0 258 + 266 1 13,14 276 3 59-66 + + The extra bits should be interpreted as a machine integer + stored with the most-significant bit first, e.g., bits 1110 + represent the value 14. + + Extra Extra Extra + Code Bits Dist Code Bits Dist Code Bits Distance + ---- ---- ---- ---- ---- ------ ---- ---- -------- + 0 0 1 10 4 33-48 20 9 1025-1536 + 1 0 2 11 4 49-64 21 9 1537-2048 + 2 0 3 12 5 65-96 22 10 2049-3072 + 3 0 4 13 5 97-128 23 10 3073-4096 + 4 1 5,6 14 6 129-192 24 11 4097-6144 + 5 1 7,8 15 6 193-256 25 11 6145-8192 + 6 2 9-12 16 7 257-384 26 12 8193-12288 + 7 2 13-16 17 7 385-512 27 12 12289-16384 + 8 3 17-24 18 8 513-768 28 13 16385-24576 + 9 3 25-32 19 8 769-1024 29 13 24577-32768 + + 3.2.6. Compression with fixed Huffman codes (BTYPE=01) + + The Huffman codes for the two alphabets are fixed, and are not + represented explicitly in the data. The Huffman code lengths + for the literal/length alphabet are: + + Lit Value Bits Codes + --------- ---- ----- + 0 - 143 8 00110000 through + 10111111 + 144 - 255 9 110010000 through + 111111111 + 256 - 279 7 0000000 through + 0010111 + 280 - 287 8 11000000 through + 11000111 + + + +Deutsch Informational [Page 12] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + The code lengths are sufficient to generate the actual codes, + as described above; we show the codes in the table for added + clarity. Literal/length values 286-287 will never actually + occur in the compressed data, but participate in the code + construction. + + Distance codes 0-31 are represented by (fixed-length) 5-bit + codes, with possible additional bits as shown in the table + shown in Paragraph 3.2.5, above. Note that distance codes 30- + 31 will never actually occur in the compressed data. + + 3.2.7. Compression with dynamic Huffman codes (BTYPE=10) + + The Huffman codes for the two alphabets appear in the block + immediately after the header bits and before the actual + compressed data, first the literal/length code and then the + distance code. Each code is defined by a sequence of code + lengths, as discussed in Paragraph 3.2.2, above. For even + greater compactness, the code length sequences themselves are + compressed using a Huffman code. The alphabet for code lengths + is as follows: + + 0 - 15: Represent code lengths of 0 - 15 + 16: Copy the previous code length 3 - 6 times. + The next 2 bits indicate repeat length + (0 = 3, ... , 3 = 6) + Example: Codes 8, 16 (+2 bits 11), + 16 (+2 bits 10) will expand to + 12 code lengths of 8 (1 + 6 + 5) + 17: Repeat a code length of 0 for 3 - 10 times. + (3 bits of length) + 18: Repeat a code length of 0 for 11 - 138 times + (7 bits of length) + + A code length of 0 indicates that the corresponding symbol in + the literal/length or distance alphabet will not occur in the + block, and should not participate in the Huffman code + construction algorithm given earlier. If only one distance + code is used, it is encoded using one bit, not zero bits; in + this case there is a single code length of one, with one unused + code. One distance code of zero bits means that there are no + distance codes used at all (the data is all literals). + + We can now define the format of the block: + + 5 Bits: HLIT, # of Literal/Length codes - 257 (257 - 286) + 5 Bits: HDIST, # of Distance codes - 1 (1 - 32) + 4 Bits: HCLEN, # of Code Length codes - 4 (4 - 19) + + + +Deutsch Informational [Page 13] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + (HCLEN + 4) x 3 bits: code lengths for the code length + alphabet given just above, in the order: 16, 17, 18, + 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 + + These code lengths are interpreted as 3-bit integers + (0-7); as above, a code length of 0 means the + corresponding symbol (literal/length or distance code + length) is not used. + + HLIT + 257 code lengths for the literal/length alphabet, + encoded using the code length Huffman code + + HDIST + 1 code lengths for the distance alphabet, + encoded using the code length Huffman code + + The actual compressed data of the block, + encoded using the literal/length and distance Huffman + codes + + The literal/length symbol 256 (end of data), + encoded using the literal/length Huffman code + + The code length repeat codes can cross from HLIT + 257 to the + HDIST + 1 code lengths. In other words, all code lengths form + a single sequence of HLIT + HDIST + 258 values. + + 3.3. Compliance + + A compressor may limit further the ranges of values specified in + the previous section and still be compliant; for example, it may + limit the range of backward pointers to some value smaller than + 32K. Similarly, a compressor may limit the size of blocks so that + a compressible block fits in memory. + + A compliant decompressor must accept the full range of possible + values defined in the previous section, and must accept blocks of + arbitrary size. + +4. Compression algorithm details + + While it is the intent of this document to define the "deflate" + compressed data format without reference to any particular + compression algorithm, the format is related to the compressed + formats produced by LZ77 (Lempel-Ziv 1977, see reference [2] below); + since many variations of LZ77 are patented, it is strongly + recommended that the implementor of a compressor follow the general + algorithm presented here, which is known not to be patented per se. + The material in this section is not part of the definition of the + + + +Deutsch Informational [Page 14] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + + specification per se, and a compressor need not follow it in order to + be compliant. + + The compressor terminates a block when it determines that starting a + new block with fresh trees would be useful, or when the block size + fills up the compressor's block buffer. + + The compressor uses a chained hash table to find duplicated strings, + using a hash function that operates on 3-byte sequences. At any + given point during compression, let XYZ be the next 3 input bytes to + be examined (not necessarily all different, of course). First, the + compressor examines the hash chain for XYZ. If the chain is empty, + the compressor simply writes out X as a literal byte and advances one + byte in the input. If the hash chain is not empty, indicating that + the sequence XYZ (or, if we are unlucky, some other 3 bytes with the + same hash function value) has occurred recently, the compressor + compares all strings on the XYZ hash chain with the actual input data + sequence starting at the current point, and selects the longest + match. + + The compressor searches the hash chains starting with the most recent + strings, to favor small distances and thus take advantage of the + Huffman encoding. The hash chains are singly linked. There are no + deletions from the hash chains; the algorithm simply discards matches + that are too old. To avoid a worst-case situation, very long hash + chains are arbitrarily truncated at a certain length, determined by a + run-time parameter. + + To improve overall compression, the compressor optionally defers the + selection of matches ("lazy matching"): after a match of length N has + been found, the compressor searches for a longer match starting at + the next input byte. If it finds a longer match, it truncates the + previous match to a length of one (thus producing a single literal + byte) and then emits the longer match. Otherwise, it emits the + original match, and, as described above, advances N bytes before + continuing. + + Run-time parameters also control this "lazy match" procedure. If + compression ratio is most important, the compressor attempts a + complete second search regardless of the length of the first match. + In the normal case, if the current match is "long enough", the + compressor reduces the search for a longer match, thus speeding up + the process. If speed is most important, the compressor inserts new + strings in the hash table only when no match was found, or when the + match is not "too long". This degrades the compression ratio but + saves time since there are both fewer insertions and fewer searches. + + + + + +Deutsch Informational [Page 15] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +5. References + + [1] Huffman, D. A., "A Method for the Construction of Minimum + Redundancy Codes", Proceedings of the Institute of Radio + Engineers, September 1952, Volume 40, Number 9, pp. 1098-1101. + + [2] Ziv J., Lempel A., "A Universal Algorithm for Sequential Data + Compression", IEEE Transactions on Information Theory, Vol. 23, + No. 3, pp. 337-343. + + [3] Gailly, J.-L., and Adler, M., ZLIB documentation and sources, + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [4] Gailly, J.-L., and Adler, M., GZIP documentation and sources, + available as gzip-*.tar in ftp://prep.ai.mit.edu/pub/gnu/ + + [5] Schwartz, E. S., and Kallick, B. "Generating a canonical prefix + encoding." Comm. ACM, 7,3 (Mar. 1964), pp. 166-169. + + [6] Hirschberg and Lelewer, "Efficient decoding of prefix codes," + Comm. ACM, 33,4, April 1990, pp. 449-459. + +6. Security Considerations + + Any data compression method involves the reduction of redundancy in + the data. Consequently, any corruption of the data is likely to have + severe effects and be difficult to correct. Uncompressed text, on + the other hand, will probably still be readable despite the presence + of some corrupted bytes. + + It is recommended that systems using this data format provide some + means of validating the integrity of the compressed data. See + reference [3], for example. + +7. Source code + + Source code for a C language implementation of a "deflate" compliant + compressor and decompressor is available within the zlib package at + ftp://ftp.uu.net/pub/archiving/zip/zlib/. + +8. Acknowledgements + + Trademarks cited in this document are the property of their + respective owners. + + Phil Katz designed the deflate format. Jean-Loup Gailly and Mark + Adler wrote the related software described in this specification. + Glenn Randers-Pehrson converted this document to RFC and HTML format. + + + +Deutsch Informational [Page 16] + +RFC 1951 DEFLATE Compressed Data Format Specification May 1996 + + +9. Author's Address + + L. Peter Deutsch + Aladdin Enterprises + 203 Santa Margarita Ave. + Menlo Park, CA 94025 + + Phone: (415) 322-0103 (AM only) + FAX: (415) 322-1734 + EMail: + + Questions about the technical content of this specification can be + sent by email to: + + Jean-Loup Gailly and + Mark Adler + + Editorial comments on this specification can be sent by email to: + + L. Peter Deutsch and + Glenn Randers-Pehrson + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Deutsch Informational [Page 17] + diff --git a/test/zlib/zlib-1.2.8/doc/rfc1952.txt b/test/zlib/zlib-1.2.8/doc/rfc1952.txt new file mode 100644 index 000000000..a8e51b456 --- /dev/null +++ b/test/zlib/zlib-1.2.8/doc/rfc1952.txt @@ -0,0 +1,675 @@ + + + + + + +Network Working Group P. Deutsch +Request for Comments: 1952 Aladdin Enterprises +Category: Informational May 1996 + + + GZIP file format specification version 4.3 + +Status of This Memo + + This memo provides information for the Internet community. This memo + does not specify an Internet standard of any kind. Distribution of + this memo is unlimited. + +IESG Note: + + The IESG takes no position on the validity of any Intellectual + Property Rights statements contained in this document. + +Notices + + Copyright (c) 1996 L. Peter Deutsch + + Permission is granted to copy and distribute this document for any + purpose and without charge, including translations into other + languages and incorporation into compilations, provided that the + copyright notice and this notice are preserved, and that any + substantive changes or deletions from the original are clearly + marked. + + A pointer to the latest version of this and related documentation in + HTML format can be found at the URL + . + +Abstract + + This specification defines a lossless compressed data format that is + compatible with the widely used GZIP utility. The format includes a + cyclic redundancy check value for detecting data corruption. The + format presently uses the DEFLATE method of compression but can be + easily extended to use other compression methods. The format can be + implemented readily in a manner not covered by patents. + + + + + + + + + + +Deutsch Informational [Page 1] + +RFC 1952 GZIP File Format Specification May 1996 + + +Table of Contents + + 1. Introduction ................................................... 2 + 1.1. Purpose ................................................... 2 + 1.2. Intended audience ......................................... 3 + 1.3. Scope ..................................................... 3 + 1.4. Compliance ................................................ 3 + 1.5. Definitions of terms and conventions used ................. 3 + 1.6. Changes from previous versions ............................ 3 + 2. Detailed specification ......................................... 4 + 2.1. Overall conventions ....................................... 4 + 2.2. File format ............................................... 5 + 2.3. Member format ............................................. 5 + 2.3.1. Member header and trailer ........................... 6 + 2.3.1.1. Extra field ................................... 8 + 2.3.1.2. Compliance .................................... 9 + 3. References .................................................. 9 + 4. Security Considerations .................................... 10 + 5. Acknowledgements ........................................... 10 + 6. Author's Address ........................................... 10 + 7. Appendix: Jean-Loup Gailly's gzip utility .................. 11 + 8. Appendix: Sample CRC Code .................................. 11 + +1. Introduction + + 1.1. Purpose + + The purpose of this specification is to define a lossless + compressed data format that: + + * Is independent of CPU type, operating system, file system, + and character set, and hence can be used for interchange; + * Can compress or decompress a data stream (as opposed to a + randomly accessible file) to produce another data stream, + using only an a priori bounded amount of intermediate + storage, and hence can be used in data communications or + similar structures such as Unix filters; + * Compresses data with efficiency comparable to the best + currently available general-purpose compression methods, + and in particular considerably better than the "compress" + program; + * Can be implemented readily in a manner not covered by + patents, and hence can be practiced freely; + * Is compatible with the file format produced by the current + widely used gzip utility, in that conforming decompressors + will be able to read data produced by the existing gzip + compressor. + + + + +Deutsch Informational [Page 2] + +RFC 1952 GZIP File Format Specification May 1996 + + + The data format defined by this specification does not attempt to: + + * Provide random access to compressed data; + * Compress specialized data (e.g., raster graphics) as well as + the best currently available specialized algorithms. + + 1.2. Intended audience + + This specification is intended for use by implementors of software + to compress data into gzip format and/or decompress data from gzip + format. + + The text of the specification assumes a basic background in + programming at the level of bits and other primitive data + representations. + + 1.3. Scope + + The specification specifies a compression method and a file format + (the latter assuming only that a file can store a sequence of + arbitrary bytes). It does not specify any particular interface to + a file system or anything about character sets or encodings + (except for file names and comments, which are optional). + + 1.4. Compliance + + Unless otherwise indicated below, a compliant decompressor must be + able to accept and decompress any file that conforms to all the + specifications presented here; a compliant compressor must produce + files that conform to all the specifications presented here. The + material in the appendices is not part of the specification per se + and is not relevant to compliance. + + 1.5. Definitions of terms and conventions used + + byte: 8 bits stored or transmitted as a unit (same as an octet). + (For this specification, a byte is exactly 8 bits, even on + machines which store a character on a number of bits different + from 8.) See below for the numbering of bits within a byte. + + 1.6. Changes from previous versions + + There have been no technical changes to the gzip format since + version 4.1 of this specification. In version 4.2, some + terminology was changed, and the sample CRC code was rewritten for + clarity and to eliminate the requirement for the caller to do pre- + and post-conditioning. Version 4.3 is a conversion of the + specification to RFC style. + + + +Deutsch Informational [Page 3] + +RFC 1952 GZIP File Format Specification May 1996 + + +2. Detailed specification + + 2.1. Overall conventions + + In the diagrams below, a box like this: + + +---+ + | | <-- the vertical bars might be missing + +---+ + + represents one byte; a box like this: + + +==============+ + | | + +==============+ + + represents a variable number of bytes. + + Bytes stored within a computer do not have a "bit order", since + they are always treated as a unit. However, a byte considered as + an integer between 0 and 255 does have a most- and least- + significant bit, and since we write numbers with the most- + significant digit on the left, we also write bytes with the most- + significant bit on the left. In the diagrams below, we number the + bits of a byte so that bit 0 is the least-significant bit, i.e., + the bits are numbered: + + +--------+ + |76543210| + +--------+ + + This document does not address the issue of the order in which + bits of a byte are transmitted on a bit-sequential medium, since + the data format described here is byte- rather than bit-oriented. + + Within a computer, a number may occupy multiple bytes. All + multi-byte numbers in the format described here are stored with + the least-significant byte first (at the lower memory address). + For example, the decimal number 520 is stored as: + + 0 1 + +--------+--------+ + |00001000|00000010| + +--------+--------+ + ^ ^ + | | + | + more significant byte = 2 x 256 + + less significant byte = 8 + + + +Deutsch Informational [Page 4] + +RFC 1952 GZIP File Format Specification May 1996 + + + 2.2. File format + + A gzip file consists of a series of "members" (compressed data + sets). The format of each member is specified in the following + section. The members simply appear one after another in the file, + with no additional information before, between, or after them. + + 2.3. Member format + + Each member has the following structure: + + +---+---+---+---+---+---+---+---+---+---+ + |ID1|ID2|CM |FLG| MTIME |XFL|OS | (more-->) + +---+---+---+---+---+---+---+---+---+---+ + + (if FLG.FEXTRA set) + + +---+---+=================================+ + | XLEN |...XLEN bytes of "extra field"...| (more-->) + +---+---+=================================+ + + (if FLG.FNAME set) + + +=========================================+ + |...original file name, zero-terminated...| (more-->) + +=========================================+ + + (if FLG.FCOMMENT set) + + +===================================+ + |...file comment, zero-terminated...| (more-->) + +===================================+ + + (if FLG.FHCRC set) + + +---+---+ + | CRC16 | + +---+---+ + + +=======================+ + |...compressed blocks...| (more-->) + +=======================+ + + 0 1 2 3 4 5 6 7 + +---+---+---+---+---+---+---+---+ + | CRC32 | ISIZE | + +---+---+---+---+---+---+---+---+ + + + + +Deutsch Informational [Page 5] + +RFC 1952 GZIP File Format Specification May 1996 + + + 2.3.1. Member header and trailer + + ID1 (IDentification 1) + ID2 (IDentification 2) + These have the fixed values ID1 = 31 (0x1f, \037), ID2 = 139 + (0x8b, \213), to identify the file as being in gzip format. + + CM (Compression Method) + This identifies the compression method used in the file. CM + = 0-7 are reserved. CM = 8 denotes the "deflate" + compression method, which is the one customarily used by + gzip and which is documented elsewhere. + + FLG (FLaGs) + This flag byte is divided into individual bits as follows: + + bit 0 FTEXT + bit 1 FHCRC + bit 2 FEXTRA + bit 3 FNAME + bit 4 FCOMMENT + bit 5 reserved + bit 6 reserved + bit 7 reserved + + If FTEXT is set, the file is probably ASCII text. This is + an optional indication, which the compressor may set by + checking a small amount of the input data to see whether any + non-ASCII characters are present. In case of doubt, FTEXT + is cleared, indicating binary data. For systems which have + different file formats for ascii text and binary data, the + decompressor can use FTEXT to choose the appropriate format. + We deliberately do not specify the algorithm used to set + this bit, since a compressor always has the option of + leaving it cleared and a decompressor always has the option + of ignoring it and letting some other program handle issues + of data conversion. + + If FHCRC is set, a CRC16 for the gzip header is present, + immediately before the compressed data. The CRC16 consists + of the two least significant bytes of the CRC32 for all + bytes of the gzip header up to and not including the CRC16. + [The FHCRC bit was never set by versions of gzip up to + 1.2.4, even though it was documented with a different + meaning in gzip 1.2.4.] + + If FEXTRA is set, optional extra fields are present, as + described in a following section. + + + +Deutsch Informational [Page 6] + +RFC 1952 GZIP File Format Specification May 1996 + + + If FNAME is set, an original file name is present, + terminated by a zero byte. The name must consist of ISO + 8859-1 (LATIN-1) characters; on operating systems using + EBCDIC or any other character set for file names, the name + must be translated to the ISO LATIN-1 character set. This + is the original name of the file being compressed, with any + directory components removed, and, if the file being + compressed is on a file system with case insensitive names, + forced to lower case. There is no original file name if the + data was compressed from a source other than a named file; + for example, if the source was stdin on a Unix system, there + is no file name. + + If FCOMMENT is set, a zero-terminated file comment is + present. This comment is not interpreted; it is only + intended for human consumption. The comment must consist of + ISO 8859-1 (LATIN-1) characters. Line breaks should be + denoted by a single line feed character (10 decimal). + + Reserved FLG bits must be zero. + + MTIME (Modification TIME) + This gives the most recent modification time of the original + file being compressed. The time is in Unix format, i.e., + seconds since 00:00:00 GMT, Jan. 1, 1970. (Note that this + may cause problems for MS-DOS and other systems that use + local rather than Universal time.) If the compressed data + did not come from a file, MTIME is set to the time at which + compression started. MTIME = 0 means no time stamp is + available. + + XFL (eXtra FLags) + These flags are available for use by specific compression + methods. The "deflate" method (CM = 8) sets these flags as + follows: + + XFL = 2 - compressor used maximum compression, + slowest algorithm + XFL = 4 - compressor used fastest algorithm + + OS (Operating System) + This identifies the type of file system on which compression + took place. This may be useful in determining end-of-line + convention for text files. The currently defined values are + as follows: + + + + + + +Deutsch Informational [Page 7] + +RFC 1952 GZIP File Format Specification May 1996 + + + 0 - FAT filesystem (MS-DOS, OS/2, NT/Win32) + 1 - Amiga + 2 - VMS (or OpenVMS) + 3 - Unix + 4 - VM/CMS + 5 - Atari TOS + 6 - HPFS filesystem (OS/2, NT) + 7 - Macintosh + 8 - Z-System + 9 - CP/M + 10 - TOPS-20 + 11 - NTFS filesystem (NT) + 12 - QDOS + 13 - Acorn RISCOS + 255 - unknown + + XLEN (eXtra LENgth) + If FLG.FEXTRA is set, this gives the length of the optional + extra field. See below for details. + + CRC32 (CRC-32) + This contains a Cyclic Redundancy Check value of the + uncompressed data computed according to CRC-32 algorithm + used in the ISO 3309 standard and in section 8.1.1.6.2 of + ITU-T recommendation V.42. (See http://www.iso.ch for + ordering ISO documents. See gopher://info.itu.ch for an + online version of ITU-T V.42.) + + ISIZE (Input SIZE) + This contains the size of the original (uncompressed) input + data modulo 2^32. + + 2.3.1.1. Extra field + + If the FLG.FEXTRA bit is set, an "extra field" is present in + the header, with total length XLEN bytes. It consists of a + series of subfields, each of the form: + + +---+---+---+---+==================================+ + |SI1|SI2| LEN |... LEN bytes of subfield data ...| + +---+---+---+---+==================================+ + + SI1 and SI2 provide a subfield ID, typically two ASCII letters + with some mnemonic value. Jean-Loup Gailly + is maintaining a registry of subfield + IDs; please send him any subfield ID you wish to use. Subfield + IDs with SI2 = 0 are reserved for future use. The following + IDs are currently defined: + + + +Deutsch Informational [Page 8] + +RFC 1952 GZIP File Format Specification May 1996 + + + SI1 SI2 Data + ---------- ---------- ---- + 0x41 ('A') 0x70 ('P') Apollo file type information + + LEN gives the length of the subfield data, excluding the 4 + initial bytes. + + 2.3.1.2. Compliance + + A compliant compressor must produce files with correct ID1, + ID2, CM, CRC32, and ISIZE, but may set all the other fields in + the fixed-length part of the header to default values (255 for + OS, 0 for all others). The compressor must set all reserved + bits to zero. + + A compliant decompressor must check ID1, ID2, and CM, and + provide an error indication if any of these have incorrect + values. It must examine FEXTRA/XLEN, FNAME, FCOMMENT and FHCRC + at least so it can skip over the optional fields if they are + present. It need not examine any other part of the header or + trailer; in particular, a decompressor may ignore FTEXT and OS + and always produce binary output, and still be compliant. A + compliant decompressor must give an error indication if any + reserved bit is non-zero, since such a bit could indicate the + presence of a new field that would cause subsequent data to be + interpreted incorrectly. + +3. References + + [1] "Information Processing - 8-bit single-byte coded graphic + character sets - Part 1: Latin alphabet No.1" (ISO 8859-1:1987). + The ISO 8859-1 (Latin-1) character set is a superset of 7-bit + ASCII. Files defining this character set are available as + iso_8859-1.* in ftp://ftp.uu.net/graphics/png/documents/ + + [2] ISO 3309 + + [3] ITU-T recommendation V.42 + + [4] Deutsch, L.P.,"DEFLATE Compressed Data Format Specification", + available in ftp://ftp.uu.net/pub/archiving/zip/doc/ + + [5] Gailly, J.-L., GZIP documentation, available as gzip-*.tar in + ftp://prep.ai.mit.edu/pub/gnu/ + + [6] Sarwate, D.V., "Computation of Cyclic Redundancy Checks via Table + Look-Up", Communications of the ACM, 31(8), pp.1008-1013. + + + + +Deutsch Informational [Page 9] + +RFC 1952 GZIP File Format Specification May 1996 + + + [7] Schwaderer, W.D., "CRC Calculation", April 85 PC Tech Journal, + pp.118-133. + + [8] ftp://ftp.adelaide.edu.au/pub/rocksoft/papers/crc_v3.txt, + describing the CRC concept. + +4. Security Considerations + + Any data compression method involves the reduction of redundancy in + the data. Consequently, any corruption of the data is likely to have + severe effects and be difficult to correct. Uncompressed text, on + the other hand, will probably still be readable despite the presence + of some corrupted bytes. + + It is recommended that systems using this data format provide some + means of validating the integrity of the compressed data, such as by + setting and checking the CRC-32 check value. + +5. Acknowledgements + + Trademarks cited in this document are the property of their + respective owners. + + Jean-Loup Gailly designed the gzip format and wrote, with Mark Adler, + the related software described in this specification. Glenn + Randers-Pehrson converted this document to RFC and HTML format. + +6. Author's Address + + L. Peter Deutsch + Aladdin Enterprises + 203 Santa Margarita Ave. + Menlo Park, CA 94025 + + Phone: (415) 322-0103 (AM only) + FAX: (415) 322-1734 + EMail: + + Questions about the technical content of this specification can be + sent by email to: + + Jean-Loup Gailly and + Mark Adler + + Editorial comments on this specification can be sent by email to: + + L. Peter Deutsch and + Glenn Randers-Pehrson + + + +Deutsch Informational [Page 10] + +RFC 1952 GZIP File Format Specification May 1996 + + +7. Appendix: Jean-Loup Gailly's gzip utility + + The most widely used implementation of gzip compression, and the + original documentation on which this specification is based, were + created by Jean-Loup Gailly . Since this + implementation is a de facto standard, we mention some more of its + features here. Again, the material in this section is not part of + the specification per se, and implementations need not follow it to + be compliant. + + When compressing or decompressing a file, gzip preserves the + protection, ownership, and modification time attributes on the local + file system, since there is no provision for representing protection + attributes in the gzip file format itself. Since the file format + includes a modification time, the gzip decompressor provides a + command line switch that assigns the modification time from the file, + rather than the local modification time of the compressed input, to + the decompressed output. + +8. Appendix: Sample CRC Code + + The following sample code represents a practical implementation of + the CRC (Cyclic Redundancy Check). (See also ISO 3309 and ITU-T V.42 + for a formal specification.) + + The sample code is in the ANSI C programming language. Non C users + may find it easier to read with these hints: + + & Bitwise AND operator. + ^ Bitwise exclusive-OR operator. + >> Bitwise right shift operator. When applied to an + unsigned quantity, as here, right shift inserts zero + bit(s) at the left. + ! Logical NOT operator. + ++ "n++" increments the variable n. + 0xNNN 0x introduces a hexadecimal (base 16) constant. + Suffix L indicates a long value (at least 32 bits). + + /* Table of CRCs of all 8-bit messages. */ + unsigned long crc_table[256]; + + /* Flag: has the table been computed? Initially false. */ + int crc_table_computed = 0; + + /* Make the table for a fast CRC. */ + void make_crc_table(void) + { + unsigned long c; + + + +Deutsch Informational [Page 11] + +RFC 1952 GZIP File Format Specification May 1996 + + + int n, k; + for (n = 0; n < 256; n++) { + c = (unsigned long) n; + for (k = 0; k < 8; k++) { + if (c & 1) { + c = 0xedb88320L ^ (c >> 1); + } else { + c = c >> 1; + } + } + crc_table[n] = c; + } + crc_table_computed = 1; + } + + /* + Update a running crc with the bytes buf[0..len-1] and return + the updated crc. The crc should be initialized to zero. Pre- and + post-conditioning (one's complement) is performed within this + function so it shouldn't be done by the caller. Usage example: + + unsigned long crc = 0L; + + while (read_buffer(buffer, length) != EOF) { + crc = update_crc(crc, buffer, length); + } + if (crc != original_crc) error(); + */ + unsigned long update_crc(unsigned long crc, + unsigned char *buf, int len) + { + unsigned long c = crc ^ 0xffffffffL; + int n; + + if (!crc_table_computed) + make_crc_table(); + for (n = 0; n < len; n++) { + c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); + } + return c ^ 0xffffffffL; + } + + /* Return the CRC of the bytes buf[0..len-1]. */ + unsigned long crc(unsigned char *buf, int len) + { + return update_crc(0L, buf, len); + } + + + + +Deutsch Informational [Page 12] + diff --git a/test/zlib/zlib-1.2.8/doc/txtvsbin.txt b/test/zlib/zlib-1.2.8/doc/txtvsbin.txt new file mode 100644 index 000000000..3d0f0634f --- /dev/null +++ b/test/zlib/zlib-1.2.8/doc/txtvsbin.txt @@ -0,0 +1,107 @@ +A Fast Method for Identifying Plain Text Files +============================================== + + +Introduction +------------ + +Given a file coming from an unknown source, it is sometimes desirable +to find out whether the format of that file is plain text. Although +this may appear like a simple task, a fully accurate detection of the +file type requires heavy-duty semantic analysis on the file contents. +It is, however, possible to obtain satisfactory results by employing +various heuristics. + +Previous versions of PKZip and other zip-compatible compression tools +were using a crude detection scheme: if more than 80% (4/5) of the bytes +found in a certain buffer are within the range [7..127], the file is +labeled as plain text, otherwise it is labeled as binary. A prominent +limitation of this scheme is the restriction to Latin-based alphabets. +Other alphabets, like Greek, Cyrillic or Asian, make extensive use of +the bytes within the range [128..255], and texts using these alphabets +are most often misidentified by this scheme; in other words, the rate +of false negatives is sometimes too high, which means that the recall +is low. Another weakness of this scheme is a reduced precision, due to +the false positives that may occur when binary files containing large +amounts of textual characters are misidentified as plain text. + +In this article we propose a new, simple detection scheme that features +a much increased precision and a near-100% recall. This scheme is +designed to work on ASCII, Unicode and other ASCII-derived alphabets, +and it handles single-byte encodings (ISO-8859, MacRoman, KOI8, etc.) +and variable-sized encodings (ISO-2022, UTF-8, etc.). Wider encodings +(UCS-2/UTF-16 and UCS-4/UTF-32) are not handled, however. + + +The Algorithm +------------- + +The algorithm works by dividing the set of bytecodes [0..255] into three +categories: +- The white list of textual bytecodes: + 9 (TAB), 10 (LF), 13 (CR), 32 (SPACE) to 255. +- The gray list of tolerated bytecodes: + 7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB), 27 (ESC). +- The black list of undesired, non-textual bytecodes: + 0 (NUL) to 6, 14 to 31. + +If a file contains at least one byte that belongs to the white list and +no byte that belongs to the black list, then the file is categorized as +plain text; otherwise, it is categorized as binary. (The boundary case, +when the file is empty, automatically falls into the latter category.) + + +Rationale +--------- + +The idea behind this algorithm relies on two observations. + +The first observation is that, although the full range of 7-bit codes +[0..127] is properly specified by the ASCII standard, most control +characters in the range [0..31] are not used in practice. The only +widely-used, almost universally-portable control codes are 9 (TAB), +10 (LF) and 13 (CR). There are a few more control codes that are +recognized on a reduced range of platforms and text viewers/editors: +7 (BEL), 8 (BS), 11 (VT), 12 (FF), 26 (SUB) and 27 (ESC); but these +codes are rarely (if ever) used alone, without being accompanied by +some printable text. Even the newer, portable text formats such as +XML avoid using control characters outside the list mentioned here. + +The second observation is that most of the binary files tend to contain +control characters, especially 0 (NUL). Even though the older text +detection schemes observe the presence of non-ASCII codes from the range +[128..255], the precision rarely has to suffer if this upper range is +labeled as textual, because the files that are genuinely binary tend to +contain both control characters and codes from the upper range. On the +other hand, the upper range needs to be labeled as textual, because it +is used by virtually all ASCII extensions. In particular, this range is +used for encoding non-Latin scripts. + +Since there is no counting involved, other than simply observing the +presence or the absence of some byte values, the algorithm produces +consistent results, regardless what alphabet encoding is being used. +(If counting were involved, it could be possible to obtain different +results on a text encoded, say, using ISO-8859-16 versus UTF-8.) + +There is an extra category of plain text files that are "polluted" with +one or more black-listed codes, either by mistake or by peculiar design +considerations. In such cases, a scheme that tolerates a small fraction +of black-listed codes would provide an increased recall (i.e. more true +positives). This, however, incurs a reduced precision overall, since +false positives are more likely to appear in binary files that contain +large chunks of textual data. Furthermore, "polluted" plain text should +be regarded as binary by general-purpose text detection schemes, because +general-purpose text processing algorithms might not be applicable. +Under this premise, it is safe to say that our detection method provides +a near-100% recall. + +Experiments have been run on many files coming from various platforms +and applications. We tried plain text files, system logs, source code, +formatted office documents, compiled object code, etc. The results +confirm the optimistic assumptions about the capabilities of this +algorithm. + + +-- +Cosmin Truta +Last updated: 2006-May-28 diff --git a/test/zlib/zlib-1.2.8/examples/README.examples b/test/zlib/zlib-1.2.8/examples/README.examples new file mode 100644 index 000000000..56a31714e --- /dev/null +++ b/test/zlib/zlib-1.2.8/examples/README.examples @@ -0,0 +1,49 @@ +This directory contains examples of the use of zlib and other relevant +programs and documentation. + +enough.c + calculation and justification of ENOUGH parameter in inftrees.h + - calculates the maximum table space used in inflate tree + construction over all possible Huffman codes + +fitblk.c + compress just enough input to nearly fill a requested output size + - zlib isn't designed to do this, but fitblk does it anyway + +gun.c + uncompress a gzip file + - illustrates the use of inflateBack() for high speed file-to-file + decompression using call-back functions + - is approximately twice as fast as gzip -d + - also provides Unix uncompress functionality, again twice as fast + +gzappend.c + append to a gzip file + - illustrates the use of the Z_BLOCK flush parameter for inflate() + - illustrates the use of deflatePrime() to start at any bit + +gzjoin.c + join gzip files without recalculating the crc or recompressing + - illustrates the use of the Z_BLOCK flush parameter for inflate() + - illustrates the use of crc32_combine() + +gzlog.c +gzlog.h + efficiently and robustly maintain a message log file in gzip format + - illustrates use of raw deflate, Z_PARTIAL_FLUSH, deflatePrime(), + and deflateSetDictionary() + - illustrates use of a gzip header extra field + +zlib_how.html + painfully comprehensive description of zpipe.c (see below) + - describes in excruciating detail the use of deflate() and inflate() + +zpipe.c + reads and writes zlib streams from stdin to stdout + - illustrates the proper use of deflate() and inflate() + - deeply commented in zlib_how.html (see above) + +zran.c + index a zlib or gzip stream and randomly access it + - illustrates the use of Z_BLOCK, inflatePrime(), and + inflateSetDictionary() to provide random access diff --git a/test/zlib/zlib-1.2.8/examples/enough.c b/test/zlib/zlib-1.2.8/examples/enough.c new file mode 100644 index 000000000..b99114430 --- /dev/null +++ b/test/zlib/zlib-1.2.8/examples/enough.c @@ -0,0 +1,572 @@ +/* enough.c -- determine the maximum size of inflate's Huffman code tables over + * all possible valid and complete Huffman codes, subject to a length limit. + * Copyright (C) 2007, 2008, 2012 Mark Adler + * Version 1.4 18 August 2012 Mark Adler + */ + +/* Version history: + 1.0 3 Jan 2007 First version (derived from codecount.c version 1.4) + 1.1 4 Jan 2007 Use faster incremental table usage computation + Prune examine() search on previously visited states + 1.2 5 Jan 2007 Comments clean up + As inflate does, decrease root for short codes + Refuse cases where inflate would increase root + 1.3 17 Feb 2008 Add argument for initial root table size + Fix bug for initial root table size == max - 1 + Use a macro to compute the history index + 1.4 18 Aug 2012 Avoid shifts more than bits in type (caused endless loop!) + Clean up comparisons of different types + Clean up code indentation + */ + +/* + Examine all possible Huffman codes for a given number of symbols and a + maximum code length in bits to determine the maximum table size for zilb's + inflate. Only complete Huffman codes are counted. + + Two codes are considered distinct if the vectors of the number of codes per + length are not identical. So permutations of the symbol assignments result + in the same code for the counting, as do permutations of the assignments of + the bit values to the codes (i.e. only canonical codes are counted). + + We build a code from shorter to longer lengths, determining how many symbols + are coded at each length. At each step, we have how many symbols remain to + be coded, what the last code length used was, and how many bit patterns of + that length remain unused. Then we add one to the code length and double the + number of unused patterns to graduate to the next code length. We then + assign all portions of the remaining symbols to that code length that + preserve the properties of a correct and eventually complete code. Those + properties are: we cannot use more bit patterns than are available; and when + all the symbols are used, there are exactly zero possible bit patterns + remaining. + + The inflate Huffman decoding algorithm uses two-level lookup tables for + speed. There is a single first-level table to decode codes up to root bits + in length (root == 9 in the current inflate implementation). The table + has 1 << root entries and is indexed by the next root bits of input. Codes + shorter than root bits have replicated table entries, so that the correct + entry is pointed to regardless of the bits that follow the short code. If + the code is longer than root bits, then the table entry points to a second- + level table. The size of that table is determined by the longest code with + that root-bit prefix. If that longest code has length len, then the table + has size 1 << (len - root), to index the remaining bits in that set of + codes. Each subsequent root-bit prefix then has its own sub-table. The + total number of table entries required by the code is calculated + incrementally as the number of codes at each bit length is populated. When + all of the codes are shorter than root bits, then root is reduced to the + longest code length, resulting in a single, smaller, one-level table. + + The inflate algorithm also provides for small values of root (relative to + the log2 of the number of symbols), where the shortest code has more bits + than root. In that case, root is increased to the length of the shortest + code. This program, by design, does not handle that case, so it is verified + that the number of symbols is less than 2^(root + 1). + + In order to speed up the examination (by about ten orders of magnitude for + the default arguments), the intermediate states in the build-up of a code + are remembered and previously visited branches are pruned. The memory + required for this will increase rapidly with the total number of symbols and + the maximum code length in bits. However this is a very small price to pay + for the vast speedup. + + First, all of the possible Huffman codes are counted, and reachable + intermediate states are noted by a non-zero count in a saved-results array. + Second, the intermediate states that lead to (root + 1) bit or longer codes + are used to look at all sub-codes from those junctures for their inflate + memory usage. (The amount of memory used is not affected by the number of + codes of root bits or less in length.) Third, the visited states in the + construction of those sub-codes and the associated calculation of the table + size is recalled in order to avoid recalculating from the same juncture. + Beginning the code examination at (root + 1) bit codes, which is enabled by + identifying the reachable nodes, accounts for about six of the orders of + magnitude of improvement for the default arguments. About another four + orders of magnitude come from not revisiting previous states. Out of + approximately 2x10^16 possible Huffman codes, only about 2x10^6 sub-codes + need to be examined to cover all of the possible table memory usage cases + for the default arguments of 286 symbols limited to 15-bit codes. + + Note that an unsigned long long type is used for counting. It is quite easy + to exceed the capacity of an eight-byte integer with a large number of + symbols and a large maximum code length, so multiple-precision arithmetic + would need to replace the unsigned long long arithmetic in that case. This + program will abort if an overflow occurs. The big_t type identifies where + the counting takes place. + + An unsigned long long type is also used for calculating the number of + possible codes remaining at the maximum length. This limits the maximum + code length to the number of bits in a long long minus the number of bits + needed to represent the symbols in a flat code. The code_t type identifies + where the bit pattern counting takes place. + */ + +#include +#include +#include +#include + +#define local static + +/* special data types */ +typedef unsigned long long big_t; /* type for code counting */ +typedef unsigned long long code_t; /* type for bit pattern counting */ +struct tab { /* type for been here check */ + size_t len; /* length of bit vector in char's */ + char *vec; /* allocated bit vector */ +}; + +/* The array for saving results, num[], is indexed with this triplet: + + syms: number of symbols remaining to code + left: number of available bit patterns at length len + len: number of bits in the codes currently being assigned + + Those indices are constrained thusly when saving results: + + syms: 3..totsym (totsym == total symbols to code) + left: 2..syms - 1, but only the evens (so syms == 8 -> 2, 4, 6) + len: 1..max - 1 (max == maximum code length in bits) + + syms == 2 is not saved since that immediately leads to a single code. left + must be even, since it represents the number of available bit patterns at + the current length, which is double the number at the previous length. + left ends at syms-1 since left == syms immediately results in a single code. + (left > sym is not allowed since that would result in an incomplete code.) + len is less than max, since the code completes immediately when len == max. + + The offset into the array is calculated for the three indices with the + first one (syms) being outermost, and the last one (len) being innermost. + We build the array with length max-1 lists for the len index, with syms-3 + of those for each symbol. There are totsym-2 of those, with each one + varying in length as a function of sym. See the calculation of index in + count() for the index, and the calculation of size in main() for the size + of the array. + + For the deflate example of 286 symbols limited to 15-bit codes, the array + has 284,284 entries, taking up 2.17 MB for an 8-byte big_t. More than + half of the space allocated for saved results is actually used -- not all + possible triplets are reached in the generation of valid Huffman codes. + */ + +/* The array for tracking visited states, done[], is itself indexed identically + to the num[] array as described above for the (syms, left, len) triplet. + Each element in the array is further indexed by the (mem, rem) doublet, + where mem is the amount of inflate table space used so far, and rem is the + remaining unused entries in the current inflate sub-table. Each indexed + element is simply one bit indicating whether the state has been visited or + not. Since the ranges for mem and rem are not known a priori, each bit + vector is of a variable size, and grows as needed to accommodate the visited + states. mem and rem are used to calculate a single index in a triangular + array. Since the range of mem is expected in the default case to be about + ten times larger than the range of rem, the array is skewed to reduce the + memory usage, with eight times the range for mem than for rem. See the + calculations for offset and bit in beenhere() for the details. + + For the deflate example of 286 symbols limited to 15-bit codes, the bit + vectors grow to total approximately 21 MB, in addition to the 4.3 MB done[] + array itself. + */ + +/* Globals to avoid propagating constants or constant pointers recursively */ +local int max; /* maximum allowed bit length for the codes */ +local int root; /* size of base code table in bits */ +local int large; /* largest code table so far */ +local size_t size; /* number of elements in num and done */ +local int *code; /* number of symbols assigned to each bit length */ +local big_t *num; /* saved results array for code counting */ +local struct tab *done; /* states already evaluated array */ + +/* Index function for num[] and done[] */ +#define INDEX(i,j,k) (((size_t)((i-1)>>1)*((i-2)>>1)+(j>>1)-1)*(max-1)+k-1) + +/* Free allocated space. Uses globals code, num, and done. */ +local void cleanup(void) +{ + size_t n; + + if (done != NULL) { + for (n = 0; n < size; n++) + if (done[n].len) + free(done[n].vec); + free(done); + } + if (num != NULL) + free(num); + if (code != NULL) + free(code); +} + +/* Return the number of possible Huffman codes using bit patterns of lengths + len through max inclusive, coding syms symbols, with left bit patterns of + length len unused -- return -1 if there is an overflow in the counting. + Keep a record of previous results in num to prevent repeating the same + calculation. Uses the globals max and num. */ +local big_t count(int syms, int len, int left) +{ + big_t sum; /* number of possible codes from this juncture */ + big_t got; /* value returned from count() */ + int least; /* least number of syms to use at this juncture */ + int most; /* most number of syms to use at this juncture */ + int use; /* number of bit patterns to use in next call */ + size_t index; /* index of this case in *num */ + + /* see if only one possible code */ + if (syms == left) + return 1; + + /* note and verify the expected state */ + assert(syms > left && left > 0 && len < max); + + /* see if we've done this one already */ + index = INDEX(syms, left, len); + got = num[index]; + if (got) + return got; /* we have -- return the saved result */ + + /* we need to use at least this many bit patterns so that the code won't be + incomplete at the next length (more bit patterns than symbols) */ + least = (left << 1) - syms; + if (least < 0) + least = 0; + + /* we can use at most this many bit patterns, lest there not be enough + available for the remaining symbols at the maximum length (if there were + no limit to the code length, this would become: most = left - 1) */ + most = (((code_t)left << (max - len)) - syms) / + (((code_t)1 << (max - len)) - 1); + + /* count all possible codes from this juncture and add them up */ + sum = 0; + for (use = least; use <= most; use++) { + got = count(syms - use, len + 1, (left - use) << 1); + sum += got; + if (got == (big_t)0 - 1 || sum < got) /* overflow */ + return (big_t)0 - 1; + } + + /* verify that all recursive calls are productive */ + assert(sum != 0); + + /* save the result and return it */ + num[index] = sum; + return sum; +} + +/* Return true if we've been here before, set to true if not. Set a bit in a + bit vector to indicate visiting this state. Each (syms,len,left) state + has a variable size bit vector indexed by (mem,rem). The bit vector is + lengthened if needed to allow setting the (mem,rem) bit. */ +local int beenhere(int syms, int len, int left, int mem, int rem) +{ + size_t index; /* index for this state's bit vector */ + size_t offset; /* offset in this state's bit vector */ + int bit; /* mask for this state's bit */ + size_t length; /* length of the bit vector in bytes */ + char *vector; /* new or enlarged bit vector */ + + /* point to vector for (syms,left,len), bit in vector for (mem,rem) */ + index = INDEX(syms, left, len); + mem -= 1 << root; + offset = (mem >> 3) + rem; + offset = ((offset * (offset + 1)) >> 1) + rem; + bit = 1 << (mem & 7); + + /* see if we've been here */ + length = done[index].len; + if (offset < length && (done[index].vec[offset] & bit) != 0) + return 1; /* done this! */ + + /* we haven't been here before -- set the bit to show we have now */ + + /* see if we need to lengthen the vector in order to set the bit */ + if (length <= offset) { + /* if we have one already, enlarge it, zero out the appended space */ + if (length) { + do { + length <<= 1; + } while (length <= offset); + vector = realloc(done[index].vec, length); + if (vector != NULL) + memset(vector + done[index].len, 0, length - done[index].len); + } + + /* otherwise we need to make a new vector and zero it out */ + else { + length = 1 << (len - root); + while (length <= offset) + length <<= 1; + vector = calloc(length, sizeof(char)); + } + + /* in either case, bail if we can't get the memory */ + if (vector == NULL) { + fputs("abort: unable to allocate enough memory\n", stderr); + cleanup(); + exit(1); + } + + /* install the new vector */ + done[index].len = length; + done[index].vec = vector; + } + + /* set the bit */ + done[index].vec[offset] |= bit; + return 0; +} + +/* Examine all possible codes from the given node (syms, len, left). Compute + the amount of memory required to build inflate's decoding tables, where the + number of code structures used so far is mem, and the number remaining in + the current sub-table is rem. Uses the globals max, code, root, large, and + done. */ +local void examine(int syms, int len, int left, int mem, int rem) +{ + int least; /* least number of syms to use at this juncture */ + int most; /* most number of syms to use at this juncture */ + int use; /* number of bit patterns to use in next call */ + + /* see if we have a complete code */ + if (syms == left) { + /* set the last code entry */ + code[len] = left; + + /* complete computation of memory used by this code */ + while (rem < left) { + left -= rem; + rem = 1 << (len - root); + mem += rem; + } + assert(rem == left); + + /* if this is a new maximum, show the entries used and the sub-code */ + if (mem > large) { + large = mem; + printf("max %d: ", mem); + for (use = root + 1; use <= max; use++) + if (code[use]) + printf("%d[%d] ", code[use], use); + putchar('\n'); + fflush(stdout); + } + + /* remove entries as we drop back down in the recursion */ + code[len] = 0; + return; + } + + /* prune the tree if we can */ + if (beenhere(syms, len, left, mem, rem)) + return; + + /* we need to use at least this many bit patterns so that the code won't be + incomplete at the next length (more bit patterns than symbols) */ + least = (left << 1) - syms; + if (least < 0) + least = 0; + + /* we can use at most this many bit patterns, lest there not be enough + available for the remaining symbols at the maximum length (if there were + no limit to the code length, this would become: most = left - 1) */ + most = (((code_t)left << (max - len)) - syms) / + (((code_t)1 << (max - len)) - 1); + + /* occupy least table spaces, creating new sub-tables as needed */ + use = least; + while (rem < use) { + use -= rem; + rem = 1 << (len - root); + mem += rem; + } + rem -= use; + + /* examine codes from here, updating table space as we go */ + for (use = least; use <= most; use++) { + code[len] = use; + examine(syms - use, len + 1, (left - use) << 1, + mem + (rem ? 1 << (len - root) : 0), rem << 1); + if (rem == 0) { + rem = 1 << (len - root); + mem += rem; + } + rem--; + } + + /* remove entries as we drop back down in the recursion */ + code[len] = 0; +} + +/* Look at all sub-codes starting with root + 1 bits. Look at only the valid + intermediate code states (syms, left, len). For each completed code, + calculate the amount of memory required by inflate to build the decoding + tables. Find the maximum amount of memory required and show the code that + requires that maximum. Uses the globals max, root, and num. */ +local void enough(int syms) +{ + int n; /* number of remaing symbols for this node */ + int left; /* number of unused bit patterns at this length */ + size_t index; /* index of this case in *num */ + + /* clear code */ + for (n = 0; n <= max; n++) + code[n] = 0; + + /* look at all (root + 1) bit and longer codes */ + large = 1 << root; /* base table */ + if (root < max) /* otherwise, there's only a base table */ + for (n = 3; n <= syms; n++) + for (left = 2; left < n; left += 2) + { + /* look at all reachable (root + 1) bit nodes, and the + resulting codes (complete at root + 2 or more) */ + index = INDEX(n, left, root + 1); + if (root + 1 < max && num[index]) /* reachable node */ + examine(n, root + 1, left, 1 << root, 0); + + /* also look at root bit codes with completions at root + 1 + bits (not saved in num, since complete), just in case */ + if (num[index - 1] && n <= left << 1) + examine((n - left) << 1, root + 1, (n - left) << 1, + 1 << root, 0); + } + + /* done */ + printf("done: maximum of %d table entries\n", large); +} + +/* + Examine and show the total number of possible Huffman codes for a given + maximum number of symbols, initial root table size, and maximum code length + in bits -- those are the command arguments in that order. The default + values are 286, 9, and 15 respectively, for the deflate literal/length code. + The possible codes are counted for each number of coded symbols from two to + the maximum. The counts for each of those and the total number of codes are + shown. The maximum number of inflate table entires is then calculated + across all possible codes. Each new maximum number of table entries and the + associated sub-code (starting at root + 1 == 10 bits) is shown. + + To count and examine Huffman codes that are not length-limited, provide a + maximum length equal to the number of symbols minus one. + + For the deflate literal/length code, use "enough". For the deflate distance + code, use "enough 30 6". + + This uses the %llu printf format to print big_t numbers, which assumes that + big_t is an unsigned long long. If the big_t type is changed (for example + to a multiple precision type), the method of printing will also need to be + updated. + */ +int main(int argc, char **argv) +{ + int syms; /* total number of symbols to code */ + int n; /* number of symbols to code for this run */ + big_t got; /* return value of count() */ + big_t sum; /* accumulated number of codes over n */ + code_t word; /* for counting bits in code_t */ + + /* set up globals for cleanup() */ + code = NULL; + num = NULL; + done = NULL; + + /* get arguments -- default to the deflate literal/length code */ + syms = 286; + root = 9; + max = 15; + if (argc > 1) { + syms = atoi(argv[1]); + if (argc > 2) { + root = atoi(argv[2]); + if (argc > 3) + max = atoi(argv[3]); + } + } + if (argc > 4 || syms < 2 || root < 1 || max < 1) { + fputs("invalid arguments, need: [sym >= 2 [root >= 1 [max >= 1]]]\n", + stderr); + return 1; + } + + /* if not restricting the code length, the longest is syms - 1 */ + if (max > syms - 1) + max = syms - 1; + + /* determine the number of bits in a code_t */ + for (n = 0, word = 1; word; n++, word <<= 1) + ; + + /* make sure that the calculation of most will not overflow */ + if (max > n || (code_t)(syms - 2) >= (((code_t)0 - 1) >> (max - 1))) { + fputs("abort: code length too long for internal types\n", stderr); + return 1; + } + + /* reject impossible code requests */ + if ((code_t)(syms - 1) > ((code_t)1 << max) - 1) { + fprintf(stderr, "%d symbols cannot be coded in %d bits\n", + syms, max); + return 1; + } + + /* allocate code vector */ + code = calloc(max + 1, sizeof(int)); + if (code == NULL) { + fputs("abort: unable to allocate enough memory\n", stderr); + return 1; + } + + /* determine size of saved results array, checking for overflows, + allocate and clear the array (set all to zero with calloc()) */ + if (syms == 2) /* iff max == 1 */ + num = NULL; /* won't be saving any results */ + else { + size = syms >> 1; + if (size > ((size_t)0 - 1) / (n = (syms - 1) >> 1) || + (size *= n, size > ((size_t)0 - 1) / (n = max - 1)) || + (size *= n, size > ((size_t)0 - 1) / sizeof(big_t)) || + (num = calloc(size, sizeof(big_t))) == NULL) { + fputs("abort: unable to allocate enough memory\n", stderr); + cleanup(); + return 1; + } + } + + /* count possible codes for all numbers of symbols, add up counts */ + sum = 0; + for (n = 2; n <= syms; n++) { + got = count(n, 1, 2); + sum += got; + if (got == (big_t)0 - 1 || sum < got) { /* overflow */ + fputs("abort: can't count that high!\n", stderr); + cleanup(); + return 1; + } + printf("%llu %d-codes\n", got, n); + } + printf("%llu total codes for 2 to %d symbols", sum, syms); + if (max < syms - 1) + printf(" (%d-bit length limit)\n", max); + else + puts(" (no length limit)"); + + /* allocate and clear done array for beenhere() */ + if (syms == 2) + done = NULL; + else if (size > ((size_t)0 - 1) / sizeof(struct tab) || + (done = calloc(size, sizeof(struct tab))) == NULL) { + fputs("abort: unable to allocate enough memory\n", stderr); + cleanup(); + return 1; + } + + /* find and show maximum inflate table usage */ + if (root > max) /* reduce root to max length */ + root = max; + if ((code_t)syms < ((code_t)1 << (root + 1))) + enough(syms); + else + puts("cannot handle minimum code lengths > root"); + + /* done */ + cleanup(); + return 0; +} diff --git a/test/zlib/zlib-1.2.8/examples/fitblk.c b/test/zlib/zlib-1.2.8/examples/fitblk.c new file mode 100644 index 000000000..c61de5c99 --- /dev/null +++ b/test/zlib/zlib-1.2.8/examples/fitblk.c @@ -0,0 +1,233 @@ +/* fitblk.c: example of fitting compressed output to a specified size + Not copyrighted -- provided to the public domain + Version 1.1 25 November 2004 Mark Adler */ + +/* Version history: + 1.0 24 Nov 2004 First version + 1.1 25 Nov 2004 Change deflateInit2() to deflateInit() + Use fixed-size, stack-allocated raw buffers + Simplify code moving compression to subroutines + Use assert() for internal errors + Add detailed description of approach + */ + +/* Approach to just fitting a requested compressed size: + + fitblk performs three compression passes on a portion of the input + data in order to determine how much of that input will compress to + nearly the requested output block size. The first pass generates + enough deflate blocks to produce output to fill the requested + output size plus a specfied excess amount (see the EXCESS define + below). The last deflate block may go quite a bit past that, but + is discarded. The second pass decompresses and recompresses just + the compressed data that fit in the requested plus excess sized + buffer. The deflate process is terminated after that amount of + input, which is less than the amount consumed on the first pass. + The last deflate block of the result will be of a comparable size + to the final product, so that the header for that deflate block and + the compression ratio for that block will be about the same as in + the final product. The third compression pass decompresses the + result of the second step, but only the compressed data up to the + requested size minus an amount to allow the compressed stream to + complete (see the MARGIN define below). That will result in a + final compressed stream whose length is less than or equal to the + requested size. Assuming sufficient input and a requested size + greater than a few hundred bytes, the shortfall will typically be + less than ten bytes. + + If the input is short enough that the first compression completes + before filling the requested output size, then that compressed + stream is return with no recompression. + + EXCESS is chosen to be just greater than the shortfall seen in a + two pass approach similar to the above. That shortfall is due to + the last deflate block compressing more efficiently with a smaller + header on the second pass. EXCESS is set to be large enough so + that there is enough uncompressed data for the second pass to fill + out the requested size, and small enough so that the final deflate + block of the second pass will be close in size to the final deflate + block of the third and final pass. MARGIN is chosen to be just + large enough to assure that the final compression has enough room + to complete in all cases. + */ + +#include +#include +#include +#include "zlib.h" + +#define local static + +/* print nastygram and leave */ +local void quit(char *why) +{ + fprintf(stderr, "fitblk abort: %s\n", why); + exit(1); +} + +#define RAWLEN 4096 /* intermediate uncompressed buffer size */ + +/* compress from file to def until provided buffer is full or end of + input reached; return last deflate() return value, or Z_ERRNO if + there was read error on the file */ +local int partcompress(FILE *in, z_streamp def) +{ + int ret, flush; + unsigned char raw[RAWLEN]; + + flush = Z_NO_FLUSH; + do { + def->avail_in = fread(raw, 1, RAWLEN, in); + if (ferror(in)) + return Z_ERRNO; + def->next_in = raw; + if (feof(in)) + flush = Z_FINISH; + ret = deflate(def, flush); + assert(ret != Z_STREAM_ERROR); + } while (def->avail_out != 0 && flush == Z_NO_FLUSH); + return ret; +} + +/* recompress from inf's input to def's output; the input for inf and + the output for def are set in those structures before calling; + return last deflate() return value, or Z_MEM_ERROR if inflate() + was not able to allocate enough memory when it needed to */ +local int recompress(z_streamp inf, z_streamp def) +{ + int ret, flush; + unsigned char raw[RAWLEN]; + + flush = Z_NO_FLUSH; + do { + /* decompress */ + inf->avail_out = RAWLEN; + inf->next_out = raw; + ret = inflate(inf, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR && + ret != Z_NEED_DICT); + if (ret == Z_MEM_ERROR) + return ret; + + /* compress what was decompresed until done or no room */ + def->avail_in = RAWLEN - inf->avail_out; + def->next_in = raw; + if (inf->avail_out != 0) + flush = Z_FINISH; + ret = deflate(def, flush); + assert(ret != Z_STREAM_ERROR); + } while (ret != Z_STREAM_END && def->avail_out != 0); + return ret; +} + +#define EXCESS 256 /* empirically determined stream overage */ +#define MARGIN 8 /* amount to back off for completion */ + +/* compress from stdin to fixed-size block on stdout */ +int main(int argc, char **argv) +{ + int ret; /* return code */ + unsigned size; /* requested fixed output block size */ + unsigned have; /* bytes written by deflate() call */ + unsigned char *blk; /* intermediate and final stream */ + unsigned char *tmp; /* close to desired size stream */ + z_stream def, inf; /* zlib deflate and inflate states */ + + /* get requested output size */ + if (argc != 2) + quit("need one argument: size of output block"); + ret = strtol(argv[1], argv + 1, 10); + if (argv[1][0] != 0) + quit("argument must be a number"); + if (ret < 8) /* 8 is minimum zlib stream size */ + quit("need positive size of 8 or greater"); + size = (unsigned)ret; + + /* allocate memory for buffers and compression engine */ + blk = malloc(size + EXCESS); + def.zalloc = Z_NULL; + def.zfree = Z_NULL; + def.opaque = Z_NULL; + ret = deflateInit(&def, Z_DEFAULT_COMPRESSION); + if (ret != Z_OK || blk == NULL) + quit("out of memory"); + + /* compress from stdin until output full, or no more input */ + def.avail_out = size + EXCESS; + def.next_out = blk; + ret = partcompress(stdin, &def); + if (ret == Z_ERRNO) + quit("error reading input"); + + /* if it all fit, then size was undersubscribed -- done! */ + if (ret == Z_STREAM_END && def.avail_out >= EXCESS) { + /* write block to stdout */ + have = size + EXCESS - def.avail_out; + if (fwrite(blk, 1, have, stdout) != have || ferror(stdout)) + quit("error writing output"); + + /* clean up and print results to stderr */ + ret = deflateEnd(&def); + assert(ret != Z_STREAM_ERROR); + free(blk); + fprintf(stderr, + "%u bytes unused out of %u requested (all input)\n", + size - have, size); + return 0; + } + + /* it didn't all fit -- set up for recompression */ + inf.zalloc = Z_NULL; + inf.zfree = Z_NULL; + inf.opaque = Z_NULL; + inf.avail_in = 0; + inf.next_in = Z_NULL; + ret = inflateInit(&inf); + tmp = malloc(size + EXCESS); + if (ret != Z_OK || tmp == NULL) + quit("out of memory"); + ret = deflateReset(&def); + assert(ret != Z_STREAM_ERROR); + + /* do first recompression close to the right amount */ + inf.avail_in = size + EXCESS; + inf.next_in = blk; + def.avail_out = size + EXCESS; + def.next_out = tmp; + ret = recompress(&inf, &def); + if (ret == Z_MEM_ERROR) + quit("out of memory"); + + /* set up for next reocmpression */ + ret = inflateReset(&inf); + assert(ret != Z_STREAM_ERROR); + ret = deflateReset(&def); + assert(ret != Z_STREAM_ERROR); + + /* do second and final recompression (third compression) */ + inf.avail_in = size - MARGIN; /* assure stream will complete */ + inf.next_in = tmp; + def.avail_out = size; + def.next_out = blk; + ret = recompress(&inf, &def); + if (ret == Z_MEM_ERROR) + quit("out of memory"); + assert(ret == Z_STREAM_END); /* otherwise MARGIN too small */ + + /* done -- write block to stdout */ + have = size - def.avail_out; + if (fwrite(blk, 1, have, stdout) != have || ferror(stdout)) + quit("error writing output"); + + /* clean up and print results to stderr */ + free(tmp); + ret = inflateEnd(&inf); + assert(ret != Z_STREAM_ERROR); + ret = deflateEnd(&def); + assert(ret != Z_STREAM_ERROR); + free(blk); + fprintf(stderr, + "%u bytes unused out of %u requested (%lu input)\n", + size - have, size, def.total_in); + return 0; +} diff --git a/test/zlib/zlib-1.2.8/examples/gun.c b/test/zlib/zlib-1.2.8/examples/gun.c new file mode 100644 index 000000000..89e484fee --- /dev/null +++ b/test/zlib/zlib-1.2.8/examples/gun.c @@ -0,0 +1,702 @@ +/* gun.c -- simple gunzip to give an example of the use of inflateBack() + * Copyright (C) 2003, 2005, 2008, 2010, 2012 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + Version 1.7 12 August 2012 Mark Adler */ + +/* Version history: + 1.0 16 Feb 2003 First version for testing of inflateBack() + 1.1 21 Feb 2005 Decompress concatenated gzip streams + Remove use of "this" variable (C++ keyword) + Fix return value for in() + Improve allocation failure checking + Add typecasting for void * structures + Add -h option for command version and usage + Add a bunch of comments + 1.2 20 Mar 2005 Add Unix compress (LZW) decompression + Copy file attributes from input file to output file + 1.3 12 Jun 2005 Add casts for error messages [Oberhumer] + 1.4 8 Dec 2006 LZW decompression speed improvements + 1.5 9 Feb 2008 Avoid warning in latest version of gcc + 1.6 17 Jan 2010 Avoid signed/unsigned comparison warnings + 1.7 12 Aug 2012 Update for z_const usage in zlib 1.2.8 + */ + +/* + gun [ -t ] [ name ... ] + + decompresses the data in the named gzip files. If no arguments are given, + gun will decompress from stdin to stdout. The names must end in .gz, -gz, + .z, -z, _z, or .Z. The uncompressed data will be written to a file name + with the suffix stripped. On success, the original file is deleted. On + failure, the output file is deleted. For most failures, the command will + continue to process the remaining names on the command line. A memory + allocation failure will abort the command. If -t is specified, then the + listed files or stdin will be tested as gzip files for integrity (without + checking for a proper suffix), no output will be written, and no files + will be deleted. + + Like gzip, gun allows concatenated gzip streams and will decompress them, + writing all of the uncompressed data to the output. Unlike gzip, gun allows + an empty file on input, and will produce no error writing an empty output + file. + + gun will also decompress files made by Unix compress, which uses LZW + compression. These files are automatically detected by virtue of their + magic header bytes. Since the end of Unix compress stream is marked by the + end-of-file, they cannot be concantenated. If a Unix compress stream is + encountered in an input file, it is the last stream in that file. + + Like gunzip and uncompress, the file attributes of the orignal compressed + file are maintained in the final uncompressed file, to the extent that the + user permissions allow it. + + On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version + 1.2.4) is on the same file, when gun is linked with zlib 1.2.2. Also the + LZW decompression provided by gun is about twice as fast as the standard + Unix uncompress command. + */ + +/* external functions and related types and constants */ +#include /* fprintf() */ +#include /* malloc(), free() */ +#include /* strerror(), strcmp(), strlen(), memcpy() */ +#include /* errno */ +#include /* open() */ +#include /* read(), write(), close(), chown(), unlink() */ +#include +#include /* stat(), chmod() */ +#include /* utime() */ +#include "zlib.h" /* inflateBackInit(), inflateBack(), */ + /* inflateBackEnd(), crc32() */ + +/* function declaration */ +#define local static + +/* buffer constants */ +#define SIZE 32768U /* input and output buffer sizes */ +#define PIECE 16384 /* limits i/o chunks for 16-bit int case */ + +/* structure for infback() to pass to input function in() -- it maintains the + input file and a buffer of size SIZE */ +struct ind { + int infile; + unsigned char *inbuf; +}; + +/* Load input buffer, assumed to be empty, and return bytes loaded and a + pointer to them. read() is called until the buffer is full, or until it + returns end-of-file or error. Return 0 on error. */ +local unsigned in(void *in_desc, z_const unsigned char **buf) +{ + int ret; + unsigned len; + unsigned char *next; + struct ind *me = (struct ind *)in_desc; + + next = me->inbuf; + *buf = next; + len = 0; + do { + ret = PIECE; + if ((unsigned)ret > SIZE - len) + ret = (int)(SIZE - len); + ret = (int)read(me->infile, next, ret); + if (ret == -1) { + len = 0; + break; + } + next += ret; + len += ret; + } while (ret != 0 && len < SIZE); + return len; +} + +/* structure for infback() to pass to output function out() -- it maintains the + output file, a running CRC-32 check on the output and the total number of + bytes output, both for checking against the gzip trailer. (The length in + the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and + the output is greater than 4 GB.) */ +struct outd { + int outfile; + int check; /* true if checking crc and total */ + unsigned long crc; + unsigned long total; +}; + +/* Write output buffer and update the CRC-32 and total bytes written. write() + is called until all of the output is written or an error is encountered. + On success out() returns 0. For a write failure, out() returns 1. If the + output file descriptor is -1, then nothing is written. + */ +local int out(void *out_desc, unsigned char *buf, unsigned len) +{ + int ret; + struct outd *me = (struct outd *)out_desc; + + if (me->check) { + me->crc = crc32(me->crc, buf, len); + me->total += len; + } + if (me->outfile != -1) + do { + ret = PIECE; + if ((unsigned)ret > len) + ret = (int)len; + ret = (int)write(me->outfile, buf, ret); + if (ret == -1) + return 1; + buf += ret; + len -= ret; + } while (len != 0); + return 0; +} + +/* next input byte macro for use inside lunpipe() and gunpipe() */ +#define NEXT() (have ? 0 : (have = in(indp, &next)), \ + last = have ? (have--, (int)(*next++)) : -1) + +/* memory for gunpipe() and lunpipe() -- + the first 256 entries of prefix[] and suffix[] are never used, could + have offset the index, but it's faster to waste the memory */ +unsigned char inbuf[SIZE]; /* input buffer */ +unsigned char outbuf[SIZE]; /* output buffer */ +unsigned short prefix[65536]; /* index to LZW prefix string */ +unsigned char suffix[65536]; /* one-character LZW suffix */ +unsigned char match[65280 + 2]; /* buffer for reversed match or gzip + 32K sliding window */ + +/* throw out what's left in the current bits byte buffer (this is a vestigial + aspect of the compressed data format derived from an implementation that + made use of a special VAX machine instruction!) */ +#define FLUSHCODE() \ + do { \ + left = 0; \ + rem = 0; \ + if (chunk > have) { \ + chunk -= have; \ + have = 0; \ + if (NEXT() == -1) \ + break; \ + chunk--; \ + if (chunk > have) { \ + chunk = have = 0; \ + break; \ + } \ + } \ + have -= chunk; \ + next += chunk; \ + chunk = 0; \ + } while (0) + +/* Decompress a compress (LZW) file from indp to outfile. The compress magic + header (two bytes) has already been read and verified. There are have bytes + of buffered input at next. strm is used for passing error information back + to gunpipe(). + + lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of + file, read error, or write error (a write error indicated by strm->next_in + not equal to Z_NULL), or Z_DATA_ERROR for invalid input. + */ +local int lunpipe(unsigned have, z_const unsigned char *next, struct ind *indp, + int outfile, z_stream *strm) +{ + int last; /* last byte read by NEXT(), or -1 if EOF */ + unsigned chunk; /* bytes left in current chunk */ + int left; /* bits left in rem */ + unsigned rem; /* unused bits from input */ + int bits; /* current bits per code */ + unsigned code; /* code, table traversal index */ + unsigned mask; /* mask for current bits codes */ + int max; /* maximum bits per code for this stream */ + unsigned flags; /* compress flags, then block compress flag */ + unsigned end; /* last valid entry in prefix/suffix tables */ + unsigned temp; /* current code */ + unsigned prev; /* previous code */ + unsigned final; /* last character written for previous code */ + unsigned stack; /* next position for reversed string */ + unsigned outcnt; /* bytes in output buffer */ + struct outd outd; /* output structure */ + unsigned char *p; + + /* set up output */ + outd.outfile = outfile; + outd.check = 0; + + /* process remainder of compress header -- a flags byte */ + flags = NEXT(); + if (last == -1) + return Z_BUF_ERROR; + if (flags & 0x60) { + strm->msg = (char *)"unknown lzw flags set"; + return Z_DATA_ERROR; + } + max = flags & 0x1f; + if (max < 9 || max > 16) { + strm->msg = (char *)"lzw bits out of range"; + return Z_DATA_ERROR; + } + if (max == 9) /* 9 doesn't really mean 9 */ + max = 10; + flags &= 0x80; /* true if block compress */ + + /* clear table */ + bits = 9; + mask = 0x1ff; + end = flags ? 256 : 255; + + /* set up: get first 9-bit code, which is the first decompressed byte, but + don't create a table entry until the next code */ + if (NEXT() == -1) /* no compressed data is ok */ + return Z_OK; + final = prev = (unsigned)last; /* low 8 bits of code */ + if (NEXT() == -1) /* missing a bit */ + return Z_BUF_ERROR; + if (last & 1) { /* code must be < 256 */ + strm->msg = (char *)"invalid lzw code"; + return Z_DATA_ERROR; + } + rem = (unsigned)last >> 1; /* remaining 7 bits */ + left = 7; + chunk = bits - 2; /* 7 bytes left in this chunk */ + outbuf[0] = (unsigned char)final; /* write first decompressed byte */ + outcnt = 1; + + /* decode codes */ + stack = 0; + for (;;) { + /* if the table will be full after this, increment the code size */ + if (end >= mask && bits < max) { + FLUSHCODE(); + bits++; + mask <<= 1; + mask++; + } + + /* get a code of length bits */ + if (chunk == 0) /* decrement chunk modulo bits */ + chunk = bits; + code = rem; /* low bits of code */ + if (NEXT() == -1) { /* EOF is end of compressed data */ + /* write remaining buffered output */ + if (outcnt && out(&outd, outbuf, outcnt)) { + strm->next_in = outbuf; /* signal write error */ + return Z_BUF_ERROR; + } + return Z_OK; + } + code += (unsigned)last << left; /* middle (or high) bits of code */ + left += 8; + chunk--; + if (bits > left) { /* need more bits */ + if (NEXT() == -1) /* can't end in middle of code */ + return Z_BUF_ERROR; + code += (unsigned)last << left; /* high bits of code */ + left += 8; + chunk--; + } + code &= mask; /* mask to current code length */ + left -= bits; /* number of unused bits */ + rem = (unsigned)last >> (8 - left); /* unused bits from last byte */ + + /* process clear code (256) */ + if (code == 256 && flags) { + FLUSHCODE(); + bits = 9; /* initialize bits and mask */ + mask = 0x1ff; + end = 255; /* empty table */ + continue; /* get next code */ + } + + /* special code to reuse last match */ + temp = code; /* save the current code */ + if (code > end) { + /* Be picky on the allowed code here, and make sure that the code + we drop through (prev) will be a valid index so that random + input does not cause an exception. The code != end + 1 check is + empirically derived, and not checked in the original uncompress + code. If this ever causes a problem, that check could be safely + removed. Leaving this check in greatly improves gun's ability + to detect random or corrupted input after a compress header. + In any case, the prev > end check must be retained. */ + if (code != end + 1 || prev > end) { + strm->msg = (char *)"invalid lzw code"; + return Z_DATA_ERROR; + } + match[stack++] = (unsigned char)final; + code = prev; + } + + /* walk through linked list to generate output in reverse order */ + p = match + stack; + while (code >= 256) { + *p++ = suffix[code]; + code = prefix[code]; + } + stack = p - match; + match[stack++] = (unsigned char)code; + final = code; + + /* link new table entry */ + if (end < mask) { + end++; + prefix[end] = (unsigned short)prev; + suffix[end] = (unsigned char)final; + } + + /* set previous code for next iteration */ + prev = temp; + + /* write output in forward order */ + while (stack > SIZE - outcnt) { + while (outcnt < SIZE) + outbuf[outcnt++] = match[--stack]; + if (out(&outd, outbuf, outcnt)) { + strm->next_in = outbuf; /* signal write error */ + return Z_BUF_ERROR; + } + outcnt = 0; + } + p = match + stack; + do { + outbuf[outcnt++] = *--p; + } while (p > match); + stack = 0; + + /* loop for next code with final and prev as the last match, rem and + left provide the first 0..7 bits of the next code, end is the last + valid table entry */ + } +} + +/* Decompress a gzip file from infile to outfile. strm is assumed to have been + successfully initialized with inflateBackInit(). The input file may consist + of a series of gzip streams, in which case all of them will be decompressed + to the output file. If outfile is -1, then the gzip stream(s) integrity is + checked and nothing is written. + + The return value is a zlib error code: Z_MEM_ERROR if out of memory, + Z_DATA_ERROR if the header or the compressed data is invalid, or if the + trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends + prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip + stream) follows a valid gzip stream. + */ +local int gunpipe(z_stream *strm, int infile, int outfile) +{ + int ret, first, last; + unsigned have, flags, len; + z_const unsigned char *next = NULL; + struct ind ind, *indp; + struct outd outd; + + /* setup input buffer */ + ind.infile = infile; + ind.inbuf = inbuf; + indp = &ind; + + /* decompress concatenated gzip streams */ + have = 0; /* no input data read in yet */ + first = 1; /* looking for first gzip header */ + strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */ + for (;;) { + /* look for the two magic header bytes for a gzip stream */ + if (NEXT() == -1) { + ret = Z_OK; + break; /* empty gzip stream is ok */ + } + if (last != 31 || (NEXT() != 139 && last != 157)) { + strm->msg = (char *)"incorrect header check"; + ret = first ? Z_DATA_ERROR : Z_ERRNO; + break; /* not a gzip or compress header */ + } + first = 0; /* next non-header is junk */ + + /* process a compress (LZW) file -- can't be concatenated after this */ + if (last == 157) { + ret = lunpipe(have, next, indp, outfile, strm); + break; + } + + /* process remainder of gzip header */ + ret = Z_BUF_ERROR; + if (NEXT() != 8) { /* only deflate method allowed */ + if (last == -1) break; + strm->msg = (char *)"unknown compression method"; + ret = Z_DATA_ERROR; + break; + } + flags = NEXT(); /* header flags */ + NEXT(); /* discard mod time, xflgs, os */ + NEXT(); + NEXT(); + NEXT(); + NEXT(); + NEXT(); + if (last == -1) break; + if (flags & 0xe0) { + strm->msg = (char *)"unknown header flags set"; + ret = Z_DATA_ERROR; + break; + } + if (flags & 4) { /* extra field */ + len = NEXT(); + len += (unsigned)(NEXT()) << 8; + if (last == -1) break; + while (len > have) { + len -= have; + have = 0; + if (NEXT() == -1) break; + len--; + } + if (last == -1) break; + have -= len; + next += len; + } + if (flags & 8) /* file name */ + while (NEXT() != 0 && last != -1) + ; + if (flags & 16) /* comment */ + while (NEXT() != 0 && last != -1) + ; + if (flags & 2) { /* header crc */ + NEXT(); + NEXT(); + } + if (last == -1) break; + + /* set up output */ + outd.outfile = outfile; + outd.check = 1; + outd.crc = crc32(0L, Z_NULL, 0); + outd.total = 0; + + /* decompress data to output */ + strm->next_in = next; + strm->avail_in = have; + ret = inflateBack(strm, in, indp, out, &outd); + if (ret != Z_STREAM_END) break; + next = strm->next_in; + have = strm->avail_in; + strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */ + + /* check trailer */ + ret = Z_BUF_ERROR; + if (NEXT() != (int)(outd.crc & 0xff) || + NEXT() != (int)((outd.crc >> 8) & 0xff) || + NEXT() != (int)((outd.crc >> 16) & 0xff) || + NEXT() != (int)((outd.crc >> 24) & 0xff)) { + /* crc error */ + if (last != -1) { + strm->msg = (char *)"incorrect data check"; + ret = Z_DATA_ERROR; + } + break; + } + if (NEXT() != (int)(outd.total & 0xff) || + NEXT() != (int)((outd.total >> 8) & 0xff) || + NEXT() != (int)((outd.total >> 16) & 0xff) || + NEXT() != (int)((outd.total >> 24) & 0xff)) { + /* length error */ + if (last != -1) { + strm->msg = (char *)"incorrect length check"; + ret = Z_DATA_ERROR; + } + break; + } + + /* go back and look for another gzip stream */ + } + + /* clean up and return */ + return ret; +} + +/* Copy file attributes, from -> to, as best we can. This is best effort, so + no errors are reported. The mode bits, including suid, sgid, and the sticky + bit are copied (if allowed), the owner's user id and group id are copied + (again if allowed), and the access and modify times are copied. */ +local void copymeta(char *from, char *to) +{ + struct stat was; + struct utimbuf when; + + /* get all of from's Unix meta data, return if not a regular file */ + if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG) + return; + + /* set to's mode bits, ignore errors */ + (void)chmod(to, was.st_mode & 07777); + + /* copy owner's user and group, ignore errors */ + (void)chown(to, was.st_uid, was.st_gid); + + /* copy access and modify times, ignore errors */ + when.actime = was.st_atime; + when.modtime = was.st_mtime; + (void)utime(to, &when); +} + +/* Decompress the file inname to the file outnname, of if test is true, just + decompress without writing and check the gzip trailer for integrity. If + inname is NULL or an empty string, read from stdin. If outname is NULL or + an empty string, write to stdout. strm is a pre-initialized inflateBack + structure. When appropriate, copy the file attributes from inname to + outname. + + gunzip() returns 1 if there is an out-of-memory error or an unexpected + return code from gunpipe(). Otherwise it returns 0. + */ +local int gunzip(z_stream *strm, char *inname, char *outname, int test) +{ + int ret; + int infile, outfile; + + /* open files */ + if (inname == NULL || *inname == 0) { + inname = "-"; + infile = 0; /* stdin */ + } + else { + infile = open(inname, O_RDONLY, 0); + if (infile == -1) { + fprintf(stderr, "gun cannot open %s\n", inname); + return 0; + } + } + if (test) + outfile = -1; + else if (outname == NULL || *outname == 0) { + outname = "-"; + outfile = 1; /* stdout */ + } + else { + outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666); + if (outfile == -1) { + close(infile); + fprintf(stderr, "gun cannot create %s\n", outname); + return 0; + } + } + errno = 0; + + /* decompress */ + ret = gunpipe(strm, infile, outfile); + if (outfile > 2) close(outfile); + if (infile > 2) close(infile); + + /* interpret result */ + switch (ret) { + case Z_OK: + case Z_ERRNO: + if (infile > 2 && outfile > 2) { + copymeta(inname, outname); /* copy attributes */ + unlink(inname); + } + if (ret == Z_ERRNO) + fprintf(stderr, "gun warning: trailing garbage ignored in %s\n", + inname); + break; + case Z_DATA_ERROR: + if (outfile > 2) unlink(outname); + fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg); + break; + case Z_MEM_ERROR: + if (outfile > 2) unlink(outname); + fprintf(stderr, "gun out of memory error--aborting\n"); + return 1; + case Z_BUF_ERROR: + if (outfile > 2) unlink(outname); + if (strm->next_in != Z_NULL) { + fprintf(stderr, "gun write error on %s: %s\n", + outname, strerror(errno)); + } + else if (errno) { + fprintf(stderr, "gun read error on %s: %s\n", + inname, strerror(errno)); + } + else { + fprintf(stderr, "gun unexpected end of file on %s\n", + inname); + } + break; + default: + if (outfile > 2) unlink(outname); + fprintf(stderr, "gun internal error--aborting\n"); + return 1; + } + return 0; +} + +/* Process the gun command line arguments. See the command syntax near the + beginning of this source file. */ +int main(int argc, char **argv) +{ + int ret, len, test; + char *outname; + unsigned char *window; + z_stream strm; + + /* initialize inflateBack state for repeated use */ + window = match; /* reuse LZW match buffer */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = inflateBackInit(&strm, 15, window); + if (ret != Z_OK) { + fprintf(stderr, "gun out of memory error--aborting\n"); + return 1; + } + + /* decompress each file to the same name with the suffix removed */ + argc--; + argv++; + test = 0; + if (argc && strcmp(*argv, "-h") == 0) { + fprintf(stderr, "gun 1.6 (17 Jan 2010)\n"); + fprintf(stderr, "Copyright (C) 2003-2010 Mark Adler\n"); + fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n"); + return 0; + } + if (argc && strcmp(*argv, "-t") == 0) { + test = 1; + argc--; + argv++; + } + if (argc) + do { + if (test) + outname = NULL; + else { + len = (int)strlen(*argv); + if (strcmp(*argv + len - 3, ".gz") == 0 || + strcmp(*argv + len - 3, "-gz") == 0) + len -= 3; + else if (strcmp(*argv + len - 2, ".z") == 0 || + strcmp(*argv + len - 2, "-z") == 0 || + strcmp(*argv + len - 2, "_z") == 0 || + strcmp(*argv + len - 2, ".Z") == 0) + len -= 2; + else { + fprintf(stderr, "gun error: no gz type on %s--skipping\n", + *argv); + continue; + } + outname = malloc(len + 1); + if (outname == NULL) { + fprintf(stderr, "gun out of memory error--aborting\n"); + ret = 1; + break; + } + memcpy(outname, *argv, len); + outname[len] = 0; + } + ret = gunzip(&strm, *argv, outname, test); + if (outname != NULL) free(outname); + if (ret) break; + } while (argv++, --argc); + else + ret = gunzip(&strm, NULL, NULL, test); + + /* clean up */ + inflateBackEnd(&strm); + return ret; +} diff --git a/test/zlib/zlib-1.2.8/examples/gzappend.c b/test/zlib/zlib-1.2.8/examples/gzappend.c new file mode 100644 index 000000000..662dec379 --- /dev/null +++ b/test/zlib/zlib-1.2.8/examples/gzappend.c @@ -0,0 +1,504 @@ +/* gzappend -- command to append to a gzip file + + Copyright (C) 2003, 2012 Mark Adler, all rights reserved + version 1.2, 11 Oct 2012 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + +/* + * Change history: + * + * 1.0 19 Oct 2003 - First version + * 1.1 4 Nov 2003 - Expand and clarify some comments and notes + * - Add version and copyright to help + * - Send help to stdout instead of stderr + * - Add some preemptive typecasts + * - Add L to constants in lseek() calls + * - Remove some debugging information in error messages + * - Use new data_type definition for zlib 1.2.1 + * - Simplfy and unify file operations + * - Finish off gzip file in gztack() + * - Use deflatePrime() instead of adding empty blocks + * - Keep gzip file clean on appended file read errors + * - Use in-place rotate instead of auxiliary buffer + * (Why you ask? Because it was fun to write!) + * 1.2 11 Oct 2012 - Fix for proper z_const usage + * - Check for input buffer malloc failure + */ + +/* + gzappend takes a gzip file and appends to it, compressing files from the + command line or data from stdin. The gzip file is written to directly, to + avoid copying that file, in case it's large. Note that this results in the + unfriendly behavior that if gzappend fails, the gzip file is corrupted. + + This program was written to illustrate the use of the new Z_BLOCK option of + zlib 1.2.x's inflate() function. This option returns from inflate() at each + block boundary to facilitate locating and modifying the last block bit at + the start of the final deflate block. Also whether using Z_BLOCK or not, + another required feature of zlib 1.2.x is that inflate() now provides the + number of unusued bits in the last input byte used. gzappend will not work + with versions of zlib earlier than 1.2.1. + + gzappend first decompresses the gzip file internally, discarding all but + the last 32K of uncompressed data, and noting the location of the last block + bit and the number of unused bits in the last byte of the compressed data. + The gzip trailer containing the CRC-32 and length of the uncompressed data + is verified. This trailer will be later overwritten. + + Then the last block bit is cleared by seeking back in the file and rewriting + the byte that contains it. Seeking forward, the last byte of the compressed + data is saved along with the number of unused bits to initialize deflate. + + A deflate process is initialized, using the last 32K of the uncompressed + data from the gzip file to initialize the dictionary. If the total + uncompressed data was less than 32K, then all of it is used to initialize + the dictionary. The deflate output bit buffer is also initialized with the + last bits from the original deflate stream. From here on, the data to + append is simply compressed using deflate, and written to the gzip file. + When that is complete, the new CRC-32 and uncompressed length are written + as the trailer of the gzip file. + */ + +#include +#include +#include +#include +#include +#include "zlib.h" + +#define local static +#define LGCHUNK 14 +#define CHUNK (1U << LGCHUNK) +#define DSIZE 32768U + +/* print an error message and terminate with extreme prejudice */ +local void bye(char *msg1, char *msg2) +{ + fprintf(stderr, "gzappend error: %s%s\n", msg1, msg2); + exit(1); +} + +/* return the greatest common divisor of a and b using Euclid's algorithm, + modified to be fast when one argument much greater than the other, and + coded to avoid unnecessary swapping */ +local unsigned gcd(unsigned a, unsigned b) +{ + unsigned c; + + while (a && b) + if (a > b) { + c = b; + while (a - c >= c) + c <<= 1; + a -= c; + } + else { + c = a; + while (b - c >= c) + c <<= 1; + b -= c; + } + return a + b; +} + +/* rotate list[0..len-1] left by rot positions, in place */ +local void rotate(unsigned char *list, unsigned len, unsigned rot) +{ + unsigned char tmp; + unsigned cycles; + unsigned char *start, *last, *to, *from; + + /* normalize rot and handle degenerate cases */ + if (len < 2) return; + if (rot >= len) rot %= len; + if (rot == 0) return; + + /* pointer to last entry in list */ + last = list + (len - 1); + + /* do simple left shift by one */ + if (rot == 1) { + tmp = *list; + memcpy(list, list + 1, len - 1); + *last = tmp; + return; + } + + /* do simple right shift by one */ + if (rot == len - 1) { + tmp = *last; + memmove(list + 1, list, len - 1); + *list = tmp; + return; + } + + /* otherwise do rotate as a set of cycles in place */ + cycles = gcd(len, rot); /* number of cycles */ + do { + start = from = list + cycles; /* start index is arbitrary */ + tmp = *from; /* save entry to be overwritten */ + for (;;) { + to = from; /* next step in cycle */ + from += rot; /* go right rot positions */ + if (from > last) from -= len; /* (pointer better not wrap) */ + if (from == start) break; /* all but one shifted */ + *to = *from; /* shift left */ + } + *to = tmp; /* complete the circle */ + } while (--cycles); +} + +/* structure for gzip file read operations */ +typedef struct { + int fd; /* file descriptor */ + int size; /* 1 << size is bytes in buf */ + unsigned left; /* bytes available at next */ + unsigned char *buf; /* buffer */ + z_const unsigned char *next; /* next byte in buffer */ + char *name; /* file name for error messages */ +} file; + +/* reload buffer */ +local int readin(file *in) +{ + int len; + + len = read(in->fd, in->buf, 1 << in->size); + if (len == -1) bye("error reading ", in->name); + in->left = (unsigned)len; + in->next = in->buf; + return len; +} + +/* read from file in, exit if end-of-file */ +local int readmore(file *in) +{ + if (readin(in) == 0) bye("unexpected end of ", in->name); + return 0; +} + +#define read1(in) (in->left == 0 ? readmore(in) : 0, \ + in->left--, *(in->next)++) + +/* skip over n bytes of in */ +local void skip(file *in, unsigned n) +{ + unsigned bypass; + + if (n > in->left) { + n -= in->left; + bypass = n & ~((1U << in->size) - 1); + if (bypass) { + if (lseek(in->fd, (off_t)bypass, SEEK_CUR) == -1) + bye("seeking ", in->name); + n -= bypass; + } + readmore(in); + if (n > in->left) + bye("unexpected end of ", in->name); + } + in->left -= n; + in->next += n; +} + +/* read a four-byte unsigned integer, little-endian, from in */ +unsigned long read4(file *in) +{ + unsigned long val; + + val = read1(in); + val += (unsigned)read1(in) << 8; + val += (unsigned long)read1(in) << 16; + val += (unsigned long)read1(in) << 24; + return val; +} + +/* skip over gzip header */ +local void gzheader(file *in) +{ + int flags; + unsigned n; + + if (read1(in) != 31 || read1(in) != 139) bye(in->name, " not a gzip file"); + if (read1(in) != 8) bye("unknown compression method in", in->name); + flags = read1(in); + if (flags & 0xe0) bye("unknown header flags set in", in->name); + skip(in, 6); + if (flags & 4) { + n = read1(in); + n += (unsigned)(read1(in)) << 8; + skip(in, n); + } + if (flags & 8) while (read1(in) != 0) ; + if (flags & 16) while (read1(in) != 0) ; + if (flags & 2) skip(in, 2); +} + +/* decompress gzip file "name", return strm with a deflate stream ready to + continue compression of the data in the gzip file, and return a file + descriptor pointing to where to write the compressed data -- the deflate + stream is initialized to compress using level "level" */ +local int gzscan(char *name, z_stream *strm, int level) +{ + int ret, lastbit, left, full; + unsigned have; + unsigned long crc, tot; + unsigned char *window; + off_t lastoff, end; + file gz; + + /* open gzip file */ + gz.name = name; + gz.fd = open(name, O_RDWR, 0); + if (gz.fd == -1) bye("cannot open ", name); + gz.buf = malloc(CHUNK); + if (gz.buf == NULL) bye("out of memory", ""); + gz.size = LGCHUNK; + gz.left = 0; + + /* skip gzip header */ + gzheader(&gz); + + /* prepare to decompress */ + window = malloc(DSIZE); + if (window == NULL) bye("out of memory", ""); + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = inflateInit2(strm, -15); + if (ret != Z_OK) bye("out of memory", " or library mismatch"); + + /* decompress the deflate stream, saving append information */ + lastbit = 0; + lastoff = lseek(gz.fd, 0L, SEEK_CUR) - gz.left; + left = 0; + strm->avail_in = gz.left; + strm->next_in = gz.next; + crc = crc32(0L, Z_NULL, 0); + have = full = 0; + do { + /* if needed, get more input */ + if (strm->avail_in == 0) { + readmore(&gz); + strm->avail_in = gz.left; + strm->next_in = gz.next; + } + + /* set up output to next available section of sliding window */ + strm->avail_out = DSIZE - have; + strm->next_out = window + have; + + /* inflate and check for errors */ + ret = inflate(strm, Z_BLOCK); + if (ret == Z_STREAM_ERROR) bye("internal stream error!", ""); + if (ret == Z_MEM_ERROR) bye("out of memory", ""); + if (ret == Z_DATA_ERROR) + bye("invalid compressed data--format violated in", name); + + /* update crc and sliding window pointer */ + crc = crc32(crc, window + have, DSIZE - have - strm->avail_out); + if (strm->avail_out) + have = DSIZE - strm->avail_out; + else { + have = 0; + full = 1; + } + + /* process end of block */ + if (strm->data_type & 128) { + if (strm->data_type & 64) + left = strm->data_type & 0x1f; + else { + lastbit = strm->data_type & 0x1f; + lastoff = lseek(gz.fd, 0L, SEEK_CUR) - strm->avail_in; + } + } + } while (ret != Z_STREAM_END); + inflateEnd(strm); + gz.left = strm->avail_in; + gz.next = strm->next_in; + + /* save the location of the end of the compressed data */ + end = lseek(gz.fd, 0L, SEEK_CUR) - gz.left; + + /* check gzip trailer and save total for deflate */ + if (crc != read4(&gz)) + bye("invalid compressed data--crc mismatch in ", name); + tot = strm->total_out; + if ((tot & 0xffffffffUL) != read4(&gz)) + bye("invalid compressed data--length mismatch in", name); + + /* if not at end of file, warn */ + if (gz.left || readin(&gz)) + fprintf(stderr, + "gzappend warning: junk at end of gzip file overwritten\n"); + + /* clear last block bit */ + lseek(gz.fd, lastoff - (lastbit != 0), SEEK_SET); + if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name); + *gz.buf = (unsigned char)(*gz.buf ^ (1 << ((8 - lastbit) & 7))); + lseek(gz.fd, -1L, SEEK_CUR); + if (write(gz.fd, gz.buf, 1) != 1) bye("writing after seek to ", name); + + /* if window wrapped, build dictionary from window by rotating */ + if (full) { + rotate(window, DSIZE, have); + have = DSIZE; + } + + /* set up deflate stream with window, crc, total_in, and leftover bits */ + ret = deflateInit2(strm, level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + if (ret != Z_OK) bye("out of memory", ""); + deflateSetDictionary(strm, window, have); + strm->adler = crc; + strm->total_in = tot; + if (left) { + lseek(gz.fd, --end, SEEK_SET); + if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name); + deflatePrime(strm, 8 - left, *gz.buf); + } + lseek(gz.fd, end, SEEK_SET); + + /* clean up and return */ + free(window); + free(gz.buf); + return gz.fd; +} + +/* append file "name" to gzip file gd using deflate stream strm -- if last + is true, then finish off the deflate stream at the end */ +local void gztack(char *name, int gd, z_stream *strm, int last) +{ + int fd, len, ret; + unsigned left; + unsigned char *in, *out; + + /* open file to compress and append */ + fd = 0; + if (name != NULL) { + fd = open(name, O_RDONLY, 0); + if (fd == -1) + fprintf(stderr, "gzappend warning: %s not found, skipping ...\n", + name); + } + + /* allocate buffers */ + in = malloc(CHUNK); + out = malloc(CHUNK); + if (in == NULL || out == NULL) bye("out of memory", ""); + + /* compress input file and append to gzip file */ + do { + /* get more input */ + len = read(fd, in, CHUNK); + if (len == -1) { + fprintf(stderr, + "gzappend warning: error reading %s, skipping rest ...\n", + name); + len = 0; + } + strm->avail_in = (unsigned)len; + strm->next_in = in; + if (len) strm->adler = crc32(strm->adler, in, (unsigned)len); + + /* compress and write all available output */ + do { + strm->avail_out = CHUNK; + strm->next_out = out; + ret = deflate(strm, last && len == 0 ? Z_FINISH : Z_NO_FLUSH); + left = CHUNK - strm->avail_out; + while (left) { + len = write(gd, out + CHUNK - strm->avail_out - left, left); + if (len == -1) bye("writing gzip file", ""); + left -= (unsigned)len; + } + } while (strm->avail_out == 0 && ret != Z_STREAM_END); + } while (len != 0); + + /* write trailer after last entry */ + if (last) { + deflateEnd(strm); + out[0] = (unsigned char)(strm->adler); + out[1] = (unsigned char)(strm->adler >> 8); + out[2] = (unsigned char)(strm->adler >> 16); + out[3] = (unsigned char)(strm->adler >> 24); + out[4] = (unsigned char)(strm->total_in); + out[5] = (unsigned char)(strm->total_in >> 8); + out[6] = (unsigned char)(strm->total_in >> 16); + out[7] = (unsigned char)(strm->total_in >> 24); + len = 8; + do { + ret = write(gd, out + 8 - len, len); + if (ret == -1) bye("writing gzip file", ""); + len -= ret; + } while (len); + close(gd); + } + + /* clean up and return */ + free(out); + free(in); + if (fd > 0) close(fd); +} + +/* process the compression level option if present, scan the gzip file, and + append the specified files, or append the data from stdin if no other file + names are provided on the command line -- the gzip file must be writable + and seekable */ +int main(int argc, char **argv) +{ + int gd, level; + z_stream strm; + + /* ignore command name */ + argc--; argv++; + + /* provide usage if no arguments */ + if (*argv == NULL) { + printf( + "gzappend 1.2 (11 Oct 2012) Copyright (C) 2003, 2012 Mark Adler\n" + ); + printf( + "usage: gzappend [-level] file.gz [ addthis [ andthis ... ]]\n"); + return 0; + } + + /* set compression level */ + level = Z_DEFAULT_COMPRESSION; + if (argv[0][0] == '-') { + if (argv[0][1] < '0' || argv[0][1] > '9' || argv[0][2] != 0) + bye("invalid compression level", ""); + level = argv[0][1] - '0'; + if (*++argv == NULL) bye("no gzip file name after options", ""); + } + + /* prepare to append to gzip file */ + gd = gzscan(*argv++, &strm, level); + + /* append files on command line, or from stdin if none */ + if (*argv == NULL) + gztack(NULL, gd, &strm, 1); + else + do { + gztack(*argv, gd, &strm, argv[1] == NULL); + } while (*++argv != NULL); + return 0; +} diff --git a/test/zlib/zlib-1.2.8/examples/gzjoin.c b/test/zlib/zlib-1.2.8/examples/gzjoin.c new file mode 100644 index 000000000..89e809844 --- /dev/null +++ b/test/zlib/zlib-1.2.8/examples/gzjoin.c @@ -0,0 +1,449 @@ +/* gzjoin -- command to join gzip files into one gzip file + + Copyright (C) 2004, 2005, 2012 Mark Adler, all rights reserved + version 1.2, 14 Aug 2012 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + +/* + * Change history: + * + * 1.0 11 Dec 2004 - First version + * 1.1 12 Jun 2005 - Changed ssize_t to long for portability + * 1.2 14 Aug 2012 - Clean up for z_const usage + */ + +/* + gzjoin takes one or more gzip files on the command line and writes out a + single gzip file that will uncompress to the concatenation of the + uncompressed data from the individual gzip files. gzjoin does this without + having to recompress any of the data and without having to calculate a new + crc32 for the concatenated uncompressed data. gzjoin does however have to + decompress all of the input data in order to find the bits in the compressed + data that need to be modified to concatenate the streams. + + gzjoin does not do an integrity check on the input gzip files other than + checking the gzip header and decompressing the compressed data. They are + otherwise assumed to be complete and correct. + + Each joint between gzip files removes at least 18 bytes of previous trailer + and subsequent header, and inserts an average of about three bytes to the + compressed data in order to connect the streams. The output gzip file + has a minimal ten-byte gzip header with no file name or modification time. + + This program was written to illustrate the use of the Z_BLOCK option of + inflate() and the crc32_combine() function. gzjoin will not compile with + versions of zlib earlier than 1.2.3. + */ + +#include /* fputs(), fprintf(), fwrite(), putc() */ +#include /* exit(), malloc(), free() */ +#include /* open() */ +#include /* close(), read(), lseek() */ +#include "zlib.h" + /* crc32(), crc32_combine(), inflateInit2(), inflate(), inflateEnd() */ + +#define local static + +/* exit with an error (return a value to allow use in an expression) */ +local int bail(char *why1, char *why2) +{ + fprintf(stderr, "gzjoin error: %s%s, output incomplete\n", why1, why2); + exit(1); + return 0; +} + +/* -- simple buffered file input with access to the buffer -- */ + +#define CHUNK 32768 /* must be a power of two and fit in unsigned */ + +/* bin buffered input file type */ +typedef struct { + char *name; /* name of file for error messages */ + int fd; /* file descriptor */ + unsigned left; /* bytes remaining at next */ + unsigned char *next; /* next byte to read */ + unsigned char *buf; /* allocated buffer of length CHUNK */ +} bin; + +/* close a buffered file and free allocated memory */ +local void bclose(bin *in) +{ + if (in != NULL) { + if (in->fd != -1) + close(in->fd); + if (in->buf != NULL) + free(in->buf); + free(in); + } +} + +/* open a buffered file for input, return a pointer to type bin, or NULL on + failure */ +local bin *bopen(char *name) +{ + bin *in; + + in = malloc(sizeof(bin)); + if (in == NULL) + return NULL; + in->buf = malloc(CHUNK); + in->fd = open(name, O_RDONLY, 0); + if (in->buf == NULL || in->fd == -1) { + bclose(in); + return NULL; + } + in->left = 0; + in->next = in->buf; + in->name = name; + return in; +} + +/* load buffer from file, return -1 on read error, 0 or 1 on success, with + 1 indicating that end-of-file was reached */ +local int bload(bin *in) +{ + long len; + + if (in == NULL) + return -1; + if (in->left != 0) + return 0; + in->next = in->buf; + do { + len = (long)read(in->fd, in->buf + in->left, CHUNK - in->left); + if (len < 0) + return -1; + in->left += (unsigned)len; + } while (len != 0 && in->left < CHUNK); + return len == 0 ? 1 : 0; +} + +/* get a byte from the file, bail if end of file */ +#define bget(in) (in->left ? 0 : bload(in), \ + in->left ? (in->left--, *(in->next)++) : \ + bail("unexpected end of file on ", in->name)) + +/* get a four-byte little-endian unsigned integer from file */ +local unsigned long bget4(bin *in) +{ + unsigned long val; + + val = bget(in); + val += (unsigned long)(bget(in)) << 8; + val += (unsigned long)(bget(in)) << 16; + val += (unsigned long)(bget(in)) << 24; + return val; +} + +/* skip bytes in file */ +local void bskip(bin *in, unsigned skip) +{ + /* check pointer */ + if (in == NULL) + return; + + /* easy case -- skip bytes in buffer */ + if (skip <= in->left) { + in->left -= skip; + in->next += skip; + return; + } + + /* skip what's in buffer, discard buffer contents */ + skip -= in->left; + in->left = 0; + + /* seek past multiples of CHUNK bytes */ + if (skip > CHUNK) { + unsigned left; + + left = skip & (CHUNK - 1); + if (left == 0) { + /* exact number of chunks: seek all the way minus one byte to check + for end-of-file with a read */ + lseek(in->fd, skip - 1, SEEK_CUR); + if (read(in->fd, in->buf, 1) != 1) + bail("unexpected end of file on ", in->name); + return; + } + + /* skip the integral chunks, update skip with remainder */ + lseek(in->fd, skip - left, SEEK_CUR); + skip = left; + } + + /* read more input and skip remainder */ + bload(in); + if (skip > in->left) + bail("unexpected end of file on ", in->name); + in->left -= skip; + in->next += skip; +} + +/* -- end of buffered input functions -- */ + +/* skip the gzip header from file in */ +local void gzhead(bin *in) +{ + int flags; + + /* verify gzip magic header and compression method */ + if (bget(in) != 0x1f || bget(in) != 0x8b || bget(in) != 8) + bail(in->name, " is not a valid gzip file"); + + /* get and verify flags */ + flags = bget(in); + if ((flags & 0xe0) != 0) + bail("unknown reserved bits set in ", in->name); + + /* skip modification time, extra flags, and os */ + bskip(in, 6); + + /* skip extra field if present */ + if (flags & 4) { + unsigned len; + + len = bget(in); + len += (unsigned)(bget(in)) << 8; + bskip(in, len); + } + + /* skip file name if present */ + if (flags & 8) + while (bget(in) != 0) + ; + + /* skip comment if present */ + if (flags & 16) + while (bget(in) != 0) + ; + + /* skip header crc if present */ + if (flags & 2) + bskip(in, 2); +} + +/* write a four-byte little-endian unsigned integer to out */ +local void put4(unsigned long val, FILE *out) +{ + putc(val & 0xff, out); + putc((val >> 8) & 0xff, out); + putc((val >> 16) & 0xff, out); + putc((val >> 24) & 0xff, out); +} + +/* Load up zlib stream from buffered input, bail if end of file */ +local void zpull(z_streamp strm, bin *in) +{ + if (in->left == 0) + bload(in); + if (in->left == 0) + bail("unexpected end of file on ", in->name); + strm->avail_in = in->left; + strm->next_in = in->next; +} + +/* Write header for gzip file to out and initialize trailer. */ +local void gzinit(unsigned long *crc, unsigned long *tot, FILE *out) +{ + fwrite("\x1f\x8b\x08\0\0\0\0\0\0\xff", 1, 10, out); + *crc = crc32(0L, Z_NULL, 0); + *tot = 0; +} + +/* Copy the compressed data from name, zeroing the last block bit of the last + block if clr is true, and adding empty blocks as needed to get to a byte + boundary. If clr is false, then the last block becomes the last block of + the output, and the gzip trailer is written. crc and tot maintains the + crc and length (modulo 2^32) of the output for the trailer. The resulting + gzip file is written to out. gzinit() must be called before the first call + of gzcopy() to write the gzip header and to initialize crc and tot. */ +local void gzcopy(char *name, int clr, unsigned long *crc, unsigned long *tot, + FILE *out) +{ + int ret; /* return value from zlib functions */ + int pos; /* where the "last block" bit is in byte */ + int last; /* true if processing the last block */ + bin *in; /* buffered input file */ + unsigned char *start; /* start of compressed data in buffer */ + unsigned char *junk; /* buffer for uncompressed data -- discarded */ + z_off_t len; /* length of uncompressed data (support > 4 GB) */ + z_stream strm; /* zlib inflate stream */ + + /* open gzip file and skip header */ + in = bopen(name); + if (in == NULL) + bail("could not open ", name); + gzhead(in); + + /* allocate buffer for uncompressed data and initialize raw inflate + stream */ + junk = malloc(CHUNK); + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, -15); + if (junk == NULL || ret != Z_OK) + bail("out of memory", ""); + + /* inflate and copy compressed data, clear last-block bit if requested */ + len = 0; + zpull(&strm, in); + start = in->next; + last = start[0] & 1; + if (last && clr) + start[0] &= ~1; + strm.avail_out = 0; + for (;;) { + /* if input used and output done, write used input and get more */ + if (strm.avail_in == 0 && strm.avail_out != 0) { + fwrite(start, 1, strm.next_in - start, out); + start = in->buf; + in->left = 0; + zpull(&strm, in); + } + + /* decompress -- return early when end-of-block reached */ + strm.avail_out = CHUNK; + strm.next_out = junk; + ret = inflate(&strm, Z_BLOCK); + switch (ret) { + case Z_MEM_ERROR: + bail("out of memory", ""); + case Z_DATA_ERROR: + bail("invalid compressed data in ", in->name); + } + + /* update length of uncompressed data */ + len += CHUNK - strm.avail_out; + + /* check for block boundary (only get this when block copied out) */ + if (strm.data_type & 128) { + /* if that was the last block, then done */ + if (last) + break; + + /* number of unused bits in last byte */ + pos = strm.data_type & 7; + + /* find the next last-block bit */ + if (pos != 0) { + /* next last-block bit is in last used byte */ + pos = 0x100 >> pos; + last = strm.next_in[-1] & pos; + if (last && clr) + in->buf[strm.next_in - in->buf - 1] &= ~pos; + } + else { + /* next last-block bit is in next unused byte */ + if (strm.avail_in == 0) { + /* don't have that byte yet -- get it */ + fwrite(start, 1, strm.next_in - start, out); + start = in->buf; + in->left = 0; + zpull(&strm, in); + } + last = strm.next_in[0] & 1; + if (last && clr) + in->buf[strm.next_in - in->buf] &= ~1; + } + } + } + + /* update buffer with unused input */ + in->left = strm.avail_in; + in->next = in->buf + (strm.next_in - in->buf); + + /* copy used input, write empty blocks to get to byte boundary */ + pos = strm.data_type & 7; + fwrite(start, 1, in->next - start - 1, out); + last = in->next[-1]; + if (pos == 0 || !clr) + /* already at byte boundary, or last file: write last byte */ + putc(last, out); + else { + /* append empty blocks to last byte */ + last &= ((0x100 >> pos) - 1); /* assure unused bits are zero */ + if (pos & 1) { + /* odd -- append an empty stored block */ + putc(last, out); + if (pos == 1) + putc(0, out); /* two more bits in block header */ + fwrite("\0\0\xff\xff", 1, 4, out); + } + else { + /* even -- append 1, 2, or 3 empty fixed blocks */ + switch (pos) { + case 6: + putc(last | 8, out); + last = 0; + case 4: + putc(last | 0x20, out); + last = 0; + case 2: + putc(last | 0x80, out); + putc(0, out); + } + } + } + + /* update crc and tot */ + *crc = crc32_combine(*crc, bget4(in), len); + *tot += (unsigned long)len; + + /* clean up */ + inflateEnd(&strm); + free(junk); + bclose(in); + + /* write trailer if this is the last gzip file */ + if (!clr) { + put4(*crc, out); + put4(*tot, out); + } +} + +/* join the gzip files on the command line, write result to stdout */ +int main(int argc, char **argv) +{ + unsigned long crc, tot; /* running crc and total uncompressed length */ + + /* skip command name */ + argc--; + argv++; + + /* show usage if no arguments */ + if (argc == 0) { + fputs("gzjoin usage: gzjoin f1.gz [f2.gz [f3.gz ...]] > fjoin.gz\n", + stderr); + return 0; + } + + /* join gzip files on command line and write to stdout */ + gzinit(&crc, &tot, stdout); + while (argc--) + gzcopy(*argv++, argc, &crc, &tot, stdout); + + /* done */ + return 0; +} diff --git a/test/zlib/zlib-1.2.8/examples/gzlog.c b/test/zlib/zlib-1.2.8/examples/gzlog.c new file mode 100644 index 000000000..922f878dd --- /dev/null +++ b/test/zlib/zlib-1.2.8/examples/gzlog.c @@ -0,0 +1,1059 @@ +/* + * gzlog.c + * Copyright (C) 2004, 2008, 2012 Mark Adler, all rights reserved + * For conditions of distribution and use, see copyright notice in gzlog.h + * version 2.2, 14 Aug 2012 + */ + +/* + gzlog provides a mechanism for frequently appending short strings to a gzip + file that is efficient both in execution time and compression ratio. The + strategy is to write the short strings in an uncompressed form to the end of + the gzip file, only compressing when the amount of uncompressed data has + reached a given threshold. + + gzlog also provides protection against interruptions in the process due to + system crashes. The status of the operation is recorded in an extra field + in the gzip file, and is only updated once the gzip file is brought to a + valid state. The last data to be appended or compressed is saved in an + auxiliary file, so that if the operation is interrupted, it can be completed + the next time an append operation is attempted. + + gzlog maintains another auxiliary file with the last 32K of data from the + compressed portion, which is preloaded for the compression of the subsequent + data. This minimizes the impact to the compression ratio of appending. + */ + +/* + Operations Concept: + + Files (log name "foo"): + foo.gz -- gzip file with the complete log + foo.add -- last message to append or last data to compress + foo.dict -- dictionary of the last 32K of data for next compression + foo.temp -- temporary dictionary file for compression after this one + foo.lock -- lock file for reading and writing the other files + foo.repairs -- log file for log file recovery operations (not compressed) + + gzip file structure: + - fixed-length (no file name) header with extra field (see below) + - compressed data ending initially with empty stored block + - uncompressed data filling out originally empty stored block and + subsequent stored blocks as needed (16K max each) + - gzip trailer + - no junk at end (no other gzip streams) + + When appending data, the information in the first three items above plus the + foo.add file are sufficient to recover an interrupted append operation. The + extra field has the necessary information to restore the start of the last + stored block and determine where to append the data in the foo.add file, as + well as the crc and length of the gzip data before the append operation. + + The foo.add file is created before the gzip file is marked for append, and + deleted after the gzip file is marked as complete. So if the append + operation is interrupted, the data to add will still be there. If due to + some external force, the foo.add file gets deleted between when the append + operation was interrupted and when recovery is attempted, the gzip file will + still be restored, but without the appended data. + + When compressing data, the information in the first two items above plus the + foo.add file are sufficient to recover an interrupted compress operation. + The extra field has the necessary information to find the end of the + compressed data, and contains both the crc and length of just the compressed + data and of the complete set of data including the contents of the foo.add + file. + + Again, the foo.add file is maintained during the compress operation in case + of an interruption. If in the unlikely event the foo.add file with the data + to be compressed is missing due to some external force, a gzip file with + just the previous compressed data will be reconstructed. In this case, all + of the data that was to be compressed is lost (approximately one megabyte). + This will not occur if all that happened was an interruption of the compress + operation. + + The third state that is marked is the replacement of the old dictionary with + the new dictionary after a compress operation. Once compression is + complete, the gzip file is marked as being in the replace state. This + completes the gzip file, so an interrupt after being so marked does not + result in recompression. Then the dictionary file is replaced, and the gzip + file is marked as completed. This state prevents the possibility of + restarting compression with the wrong dictionary file. + + All three operations are wrapped by a lock/unlock procedure. In order to + gain exclusive access to the log files, first a foo.lock file must be + exclusively created. When all operations are complete, the lock is + released by deleting the foo.lock file. If when attempting to create the + lock file, it already exists and the modify time of the lock file is more + than five minutes old (set by the PATIENCE define below), then the old + lock file is considered stale and deleted, and the exclusive creation of + the lock file is retried. To assure that there are no false assessments + of the staleness of the lock file, the operations periodically touch the + lock file to update the modified date. + + Following is the definition of the extra field with all of the information + required to enable the above append and compress operations and their + recovery if interrupted. Multi-byte values are stored little endian + (consistent with the gzip format). File pointers are eight bytes long. + The crc's and lengths for the gzip trailer are four bytes long. (Note that + the length at the end of a gzip file is used for error checking only, and + for large files is actually the length modulo 2^32.) The stored block + length is two bytes long. The gzip extra field two-byte identification is + "ap" for append. It is assumed that writing the extra field to the file is + an "atomic" operation. That is, either all of the extra field is written + to the file, or none of it is, if the operation is interrupted right at the + point of updating the extra field. This is a reasonable assumption, since + the extra field is within the first 52 bytes of the file, which is smaller + than any expected block size for a mass storage device (usually 512 bytes or + larger). + + Extra field (35 bytes): + - Pointer to first stored block length -- this points to the two-byte length + of the first stored block, which is followed by the two-byte, one's + complement of that length. The stored block length is preceded by the + three-bit header of the stored block, which is the actual start of the + stored block in the deflate format. See the bit offset field below. + - Pointer to the last stored block length. This is the same as above, but + for the last stored block of the uncompressed data in the gzip file. + Initially this is the same as the first stored block length pointer. + When the stored block gets to 16K (see the MAX_STORE define), then a new + stored block as added, at which point the last stored block length pointer + is different from the first stored block length pointer. When they are + different, the first bit of the last stored block header is eight bits, or + one byte back from the block length. + - Compressed data crc and length. This is the crc and length of the data + that is in the compressed portion of the deflate stream. These are used + only in the event that the foo.add file containing the data to compress is + lost after a compress operation is interrupted. + - Total data crc and length. This is the crc and length of all of the data + stored in the gzip file, compressed and uncompressed. It is used to + reconstruct the gzip trailer when compressing, as well as when recovering + interrupted operations. + - Final stored block length. This is used to quickly find where to append, + and allows the restoration of the original final stored block state when + an append operation is interrupted. + - First stored block start as the number of bits back from the final stored + block first length byte. This value is in the range of 3..10, and is + stored as the low three bits of the final byte of the extra field after + subtracting three (0..7). This allows the last-block bit of the stored + block header to be updated when a new stored block is added, for the case + when the first stored block and the last stored block are the same. (When + they are different, the numbers of bits back is known to be eight.) This + also allows for new compressed data to be appended to the old compressed + data in the compress operation, overwriting the previous first stored + block, or for the compressed data to be terminated and a valid gzip file + reconstructed on the off chance that a compression operation was + interrupted and the data to compress in the foo.add file was deleted. + - The operation in process. This is the next two bits in the last byte (the + bits under the mask 0x18). The are interpreted as 0: nothing in process, + 1: append in process, 2: compress in process, 3: replace in process. + - The top three bits of the last byte in the extra field are reserved and + are currently set to zero. + + Main procedure: + - Exclusively create the foo.lock file using the O_CREAT and O_EXCL modes of + the system open() call. If the modify time of an existing lock file is + more than PATIENCE seconds old, then the lock file is deleted and the + exclusive create is retried. + - Load the extra field from the foo.gz file, and see if an operation was in + progress but not completed. If so, apply the recovery procedure below. + - Perform the append procedure with the provided data. + - If the uncompressed data in the foo.gz file is 1MB or more, apply the + compress procedure. + - Delete the foo.lock file. + + Append procedure: + - Put what to append in the foo.add file so that the operation can be + restarted if this procedure is interrupted. + - Mark the foo.gz extra field with the append operation in progress. + + Restore the original last-block bit and stored block length of the last + stored block from the information in the extra field, in case a previous + append operation was interrupted. + - Append the provided data to the last stored block, creating new stored + blocks as needed and updating the stored blocks last-block bits and + lengths. + - Update the crc and length with the new data, and write the gzip trailer. + - Write over the extra field (with a single write operation) with the new + pointers, lengths, and crc's, and mark the gzip file as not in process. + Though there is still a foo.add file, it will be ignored since nothing + is in process. If a foo.add file is leftover from a previously + completed operation, it is truncated when writing new data to it. + - Delete the foo.add file. + + Compress and replace procedures: + - Read all of the uncompressed data in the stored blocks in foo.gz and write + it to foo.add. Also write foo.temp with the last 32K of that data to + provide a dictionary for the next invocation of this procedure. + - Rewrite the extra field marking foo.gz with a compression in process. + * If there is no data provided to compress (due to a missing foo.add file + when recovering), reconstruct and truncate the foo.gz file to contain + only the previous compressed data and proceed to the step after the next + one. Otherwise ... + - Compress the data with the dictionary in foo.dict, and write to the + foo.gz file starting at the bit immediately following the last previously + compressed block. If there is no foo.dict, proceed anyway with the + compression at slightly reduced efficiency. (For the foo.dict file to be + missing requires some external failure beyond simply the interruption of + a compress operation.) During this process, the foo.lock file is + periodically touched to assure that that file is not considered stale by + another process before we're done. The deflation is terminated with a + non-last empty static block (10 bits long), that is then located and + written over by a last-bit-set empty stored block. + - Append the crc and length of the data in the gzip file (previously + calculated during the append operations). + - Write over the extra field with the updated stored block offsets, bits + back, crc's, and lengths, and mark foo.gz as in process for a replacement + of the dictionary. + @ Delete the foo.add file. + - Replace foo.dict with foo.temp. + - Write over the extra field, marking foo.gz as complete. + + Recovery procedure: + - If not a replace recovery, read in the foo.add file, and provide that data + to the appropriate recovery below. If there is no foo.add file, provide + a zero data length to the recovery. In that case, the append recovery + restores the foo.gz to the previous compressed + uncompressed data state. + For the the compress recovery, a missing foo.add file results in foo.gz + being restored to the previous compressed-only data state. + - Append recovery: + - Pick up append at + step above + - Compress recovery: + - Pick up compress at * step above + - Replace recovery: + - Pick up compress at @ step above + - Log the repair with a date stamp in foo.repairs + */ + +#include +#include /* rename, fopen, fprintf, fclose */ +#include /* malloc, free */ +#include /* strlen, strrchr, strcpy, strncpy, strcmp */ +#include /* open */ +#include /* lseek, read, write, close, unlink, sleep, */ + /* ftruncate, fsync */ +#include /* errno */ +#include /* time, ctime */ +#include /* stat */ +#include /* utimes */ +#include "zlib.h" /* crc32 */ + +#include "gzlog.h" /* header for external access */ + +#define local static +typedef unsigned int uint; +typedef unsigned long ulong; + +/* Macro for debugging to deterministically force recovery operations */ +#ifdef DEBUG + #include /* longjmp */ + jmp_buf gzlog_jump; /* where to go back to */ + int gzlog_bail = 0; /* which point to bail at (1..8) */ + int gzlog_count = -1; /* number of times through to wait */ +# define BAIL(n) do { if (n == gzlog_bail && gzlog_count-- == 0) \ + longjmp(gzlog_jump, gzlog_bail); } while (0) +#else +# define BAIL(n) +#endif + +/* how old the lock file can be in seconds before considering it stale */ +#define PATIENCE 300 + +/* maximum stored block size in Kbytes -- must be in 1..63 */ +#define MAX_STORE 16 + +/* number of stored Kbytes to trigger compression (must be >= 32 to allow + dictionary construction, and <= 204 * MAX_STORE, in order for >> 10 to + discard the stored block headers contribution of five bytes each) */ +#define TRIGGER 1024 + +/* size of a deflate dictionary (this cannot be changed) */ +#define DICT 32768U + +/* values for the operation (2 bits) */ +#define NO_OP 0 +#define APPEND_OP 1 +#define COMPRESS_OP 2 +#define REPLACE_OP 3 + +/* macros to extract little-endian integers from an unsigned byte buffer */ +#define PULL2(p) ((p)[0]+((uint)((p)[1])<<8)) +#define PULL4(p) (PULL2(p)+((ulong)PULL2(p+2)<<16)) +#define PULL8(p) (PULL4(p)+((off_t)PULL4(p+4)<<32)) + +/* macros to store integers into a byte buffer in little-endian order */ +#define PUT2(p,a) do {(p)[0]=a;(p)[1]=(a)>>8;} while(0) +#define PUT4(p,a) do {PUT2(p,a);PUT2(p+2,a>>16);} while(0) +#define PUT8(p,a) do {PUT4(p,a);PUT4(p+4,a>>32);} while(0) + +/* internal structure for log information */ +#define LOGID "\106\035\172" /* should be three non-zero characters */ +struct log { + char id[4]; /* contains LOGID to detect inadvertent overwrites */ + int fd; /* file descriptor for .gz file, opened read/write */ + char *path; /* allocated path, e.g. "/var/log/foo" or "foo" */ + char *end; /* end of path, for appending suffices such as ".gz" */ + off_t first; /* offset of first stored block first length byte */ + int back; /* location of first block id in bits back from first */ + uint stored; /* bytes currently in last stored block */ + off_t last; /* offset of last stored block first length byte */ + ulong ccrc; /* crc of compressed data */ + ulong clen; /* length (modulo 2^32) of compressed data */ + ulong tcrc; /* crc of total data */ + ulong tlen; /* length (modulo 2^32) of total data */ + time_t lock; /* last modify time of our lock file */ +}; + +/* gzip header for gzlog */ +local unsigned char log_gzhead[] = { + 0x1f, 0x8b, /* magic gzip id */ + 8, /* compression method is deflate */ + 4, /* there is an extra field (no file name) */ + 0, 0, 0, 0, /* no modification time provided */ + 0, 0xff, /* no extra flags, no OS specified */ + 39, 0, 'a', 'p', 35, 0 /* extra field with "ap" subfield */ + /* 35 is EXTRA, 39 is EXTRA + 4 */ +}; + +#define HEAD sizeof(log_gzhead) /* should be 16 */ + +/* initial gzip extra field content (52 == HEAD + EXTRA + 1) */ +local unsigned char log_gzext[] = { + 52, 0, 0, 0, 0, 0, 0, 0, /* offset of first stored block length */ + 52, 0, 0, 0, 0, 0, 0, 0, /* offset of last stored block length */ + 0, 0, 0, 0, 0, 0, 0, 0, /* compressed data crc and length */ + 0, 0, 0, 0, 0, 0, 0, 0, /* total data crc and length */ + 0, 0, /* final stored block data length */ + 5 /* op is NO_OP, last bit 8 bits back */ +}; + +#define EXTRA sizeof(log_gzext) /* should be 35 */ + +/* initial gzip data and trailer */ +local unsigned char log_gzbody[] = { + 1, 0, 0, 0xff, 0xff, /* empty stored block (last) */ + 0, 0, 0, 0, /* crc */ + 0, 0, 0, 0 /* uncompressed length */ +}; + +#define BODY sizeof(log_gzbody) + +/* Exclusively create foo.lock in order to negotiate exclusive access to the + foo.* files. If the modify time of an existing lock file is greater than + PATIENCE seconds in the past, then consider the lock file to have been + abandoned, delete it, and try the exclusive create again. Save the lock + file modify time for verification of ownership. Return 0 on success, or -1 + on failure, usually due to an access restriction or invalid path. Note that + if stat() or unlink() fails, it may be due to another process noticing the + abandoned lock file a smidge sooner and deleting it, so those are not + flagged as an error. */ +local int log_lock(struct log *log) +{ + int fd; + struct stat st; + + strcpy(log->end, ".lock"); + while ((fd = open(log->path, O_CREAT | O_EXCL, 0644)) < 0) { + if (errno != EEXIST) + return -1; + if (stat(log->path, &st) == 0 && time(NULL) - st.st_mtime > PATIENCE) { + unlink(log->path); + continue; + } + sleep(2); /* relinquish the CPU for two seconds while waiting */ + } + close(fd); + if (stat(log->path, &st) == 0) + log->lock = st.st_mtime; + return 0; +} + +/* Update the modify time of the lock file to now, in order to prevent another + task from thinking that the lock is stale. Save the lock file modify time + for verification of ownership. */ +local void log_touch(struct log *log) +{ + struct stat st; + + strcpy(log->end, ".lock"); + utimes(log->path, NULL); + if (stat(log->path, &st) == 0) + log->lock = st.st_mtime; +} + +/* Check the log file modify time against what is expected. Return true if + this is not our lock. If it is our lock, touch it to keep it. */ +local int log_check(struct log *log) +{ + struct stat st; + + strcpy(log->end, ".lock"); + if (stat(log->path, &st) || st.st_mtime != log->lock) + return 1; + log_touch(log); + return 0; +} + +/* Unlock a previously acquired lock, but only if it's ours. */ +local void log_unlock(struct log *log) +{ + if (log_check(log)) + return; + strcpy(log->end, ".lock"); + unlink(log->path); + log->lock = 0; +} + +/* Check the gzip header and read in the extra field, filling in the values in + the log structure. Return op on success or -1 if the gzip header was not as + expected. op is the current operation in progress last written to the extra + field. This assumes that the gzip file has already been opened, with the + file descriptor log->fd. */ +local int log_head(struct log *log) +{ + int op; + unsigned char buf[HEAD + EXTRA]; + + if (lseek(log->fd, 0, SEEK_SET) < 0 || + read(log->fd, buf, HEAD + EXTRA) != HEAD + EXTRA || + memcmp(buf, log_gzhead, HEAD)) { + return -1; + } + log->first = PULL8(buf + HEAD); + log->last = PULL8(buf + HEAD + 8); + log->ccrc = PULL4(buf + HEAD + 16); + log->clen = PULL4(buf + HEAD + 20); + log->tcrc = PULL4(buf + HEAD + 24); + log->tlen = PULL4(buf + HEAD + 28); + log->stored = PULL2(buf + HEAD + 32); + log->back = 3 + (buf[HEAD + 34] & 7); + op = (buf[HEAD + 34] >> 3) & 3; + return op; +} + +/* Write over the extra field contents, marking the operation as op. Use fsync + to assure that the device is written to, and in the requested order. This + operation, and only this operation, is assumed to be atomic in order to + assure that the log is recoverable in the event of an interruption at any + point in the process. Return -1 if the write to foo.gz failed. */ +local int log_mark(struct log *log, int op) +{ + int ret; + unsigned char ext[EXTRA]; + + PUT8(ext, log->first); + PUT8(ext + 8, log->last); + PUT4(ext + 16, log->ccrc); + PUT4(ext + 20, log->clen); + PUT4(ext + 24, log->tcrc); + PUT4(ext + 28, log->tlen); + PUT2(ext + 32, log->stored); + ext[34] = log->back - 3 + (op << 3); + fsync(log->fd); + ret = lseek(log->fd, HEAD, SEEK_SET) < 0 || + write(log->fd, ext, EXTRA) != EXTRA ? -1 : 0; + fsync(log->fd); + return ret; +} + +/* Rewrite the last block header bits and subsequent zero bits to get to a byte + boundary, setting the last block bit if last is true, and then write the + remainder of the stored block header (length and one's complement). Leave + the file pointer after the end of the last stored block data. Return -1 if + there is a read or write failure on the foo.gz file */ +local int log_last(struct log *log, int last) +{ + int back, len, mask; + unsigned char buf[6]; + + /* determine the locations of the bytes and bits to modify */ + back = log->last == log->first ? log->back : 8; + len = back > 8 ? 2 : 1; /* bytes back from log->last */ + mask = 0x80 >> ((back - 1) & 7); /* mask for block last-bit */ + + /* get the byte to modify (one or two back) into buf[0] -- don't need to + read the byte if the last-bit is eight bits back, since in that case + the entire byte will be modified */ + buf[0] = 0; + if (back != 8 && (lseek(log->fd, log->last - len, SEEK_SET) < 0 || + read(log->fd, buf, 1) != 1)) + return -1; + + /* change the last-bit of the last stored block as requested -- note + that all bits above the last-bit are set to zero, per the type bits + of a stored block being 00 and per the convention that the bits to + bring the stream to a byte boundary are also zeros */ + buf[1] = 0; + buf[2 - len] = (*buf & (mask - 1)) + (last ? mask : 0); + + /* write the modified stored block header and lengths, move the file + pointer to after the last stored block data */ + PUT2(buf + 2, log->stored); + PUT2(buf + 4, log->stored ^ 0xffff); + return lseek(log->fd, log->last - len, SEEK_SET) < 0 || + write(log->fd, buf + 2 - len, len + 4) != len + 4 || + lseek(log->fd, log->stored, SEEK_CUR) < 0 ? -1 : 0; +} + +/* Append len bytes from data to the locked and open log file. len may be zero + if recovering and no .add file was found. In that case, the previous state + of the foo.gz file is restored. The data is appended uncompressed in + deflate stored blocks. Return -1 if there was an error reading or writing + the foo.gz file. */ +local int log_append(struct log *log, unsigned char *data, size_t len) +{ + uint put; + off_t end; + unsigned char buf[8]; + + /* set the last block last-bit and length, in case recovering an + interrupted append, then position the file pointer to append to the + block */ + if (log_last(log, 1)) + return -1; + + /* append, adding stored blocks and updating the offset of the last stored + block as needed, and update the total crc and length */ + while (len) { + /* append as much as we can to the last block */ + put = (MAX_STORE << 10) - log->stored; + if (put > len) + put = (uint)len; + if (put) { + if (write(log->fd, data, put) != put) + return -1; + BAIL(1); + log->tcrc = crc32(log->tcrc, data, put); + log->tlen += put; + log->stored += put; + data += put; + len -= put; + } + + /* if we need to, add a new empty stored block */ + if (len) { + /* mark current block as not last */ + if (log_last(log, 0)) + return -1; + + /* point to new, empty stored block */ + log->last += 4 + log->stored + 1; + log->stored = 0; + } + + /* mark last block as last, update its length */ + if (log_last(log, 1)) + return -1; + BAIL(2); + } + + /* write the new crc and length trailer, and truncate just in case (could + be recovering from partial append with a missing foo.add file) */ + PUT4(buf, log->tcrc); + PUT4(buf + 4, log->tlen); + if (write(log->fd, buf, 8) != 8 || + (end = lseek(log->fd, 0, SEEK_CUR)) < 0 || ftruncate(log->fd, end)) + return -1; + + /* write the extra field, marking the log file as done, delete .add file */ + if (log_mark(log, NO_OP)) + return -1; + strcpy(log->end, ".add"); + unlink(log->path); /* ignore error, since may not exist */ + return 0; +} + +/* Replace the foo.dict file with the foo.temp file. Also delete the foo.add + file, since the compress operation may have been interrupted before that was + done. Returns 1 if memory could not be allocated, or -1 if reading or + writing foo.gz fails, or if the rename fails for some reason other than + foo.temp not existing. foo.temp not existing is a permitted error, since + the replace operation may have been interrupted after the rename is done, + but before foo.gz is marked as complete. */ +local int log_replace(struct log *log) +{ + int ret; + char *dest; + + /* delete foo.add file */ + strcpy(log->end, ".add"); + unlink(log->path); /* ignore error, since may not exist */ + BAIL(3); + + /* rename foo.name to foo.dict, replacing foo.dict if it exists */ + strcpy(log->end, ".dict"); + dest = malloc(strlen(log->path) + 1); + if (dest == NULL) + return -2; + strcpy(dest, log->path); + strcpy(log->end, ".temp"); + ret = rename(log->path, dest); + free(dest); + if (ret && errno != ENOENT) + return -1; + BAIL(4); + + /* mark the foo.gz file as done */ + return log_mark(log, NO_OP); +} + +/* Compress the len bytes at data and append the compressed data to the + foo.gz deflate data immediately after the previous compressed data. This + overwrites the previous uncompressed data, which was stored in foo.add + and is the data provided in data[0..len-1]. If this operation is + interrupted, it picks up at the start of this routine, with the foo.add + file read in again. If there is no data to compress (len == 0), then we + simply terminate the foo.gz file after the previously compressed data, + appending a final empty stored block and the gzip trailer. Return -1 if + reading or writing the log.gz file failed, or -2 if there was a memory + allocation failure. */ +local int log_compress(struct log *log, unsigned char *data, size_t len) +{ + int fd; + uint got, max; + ssize_t dict; + off_t end; + z_stream strm; + unsigned char buf[DICT]; + + /* compress and append compressed data */ + if (len) { + /* set up for deflate, allocating memory */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + if (deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -15, 8, + Z_DEFAULT_STRATEGY) != Z_OK) + return -2; + + /* read in dictionary (last 32K of data that was compressed) */ + strcpy(log->end, ".dict"); + fd = open(log->path, O_RDONLY, 0); + if (fd >= 0) { + dict = read(fd, buf, DICT); + close(fd); + if (dict < 0) { + deflateEnd(&strm); + return -1; + } + if (dict) + deflateSetDictionary(&strm, buf, (uint)dict); + } + log_touch(log); + + /* prime deflate with last bits of previous block, position write + pointer to write those bits and overwrite what follows */ + if (lseek(log->fd, log->first - (log->back > 8 ? 2 : 1), + SEEK_SET) < 0 || + read(log->fd, buf, 1) != 1 || lseek(log->fd, -1, SEEK_CUR) < 0) { + deflateEnd(&strm); + return -1; + } + deflatePrime(&strm, (8 - log->back) & 7, *buf); + + /* compress, finishing with a partial non-last empty static block */ + strm.next_in = data; + max = (((uint)0 - 1) >> 1) + 1; /* in case int smaller than size_t */ + do { + strm.avail_in = len > max ? max : (uint)len; + len -= strm.avail_in; + do { + strm.avail_out = DICT; + strm.next_out = buf; + deflate(&strm, len ? Z_NO_FLUSH : Z_PARTIAL_FLUSH); + got = DICT - strm.avail_out; + if (got && write(log->fd, buf, got) != got) { + deflateEnd(&strm); + return -1; + } + log_touch(log); + } while (strm.avail_out == 0); + } while (len); + deflateEnd(&strm); + BAIL(5); + + /* find start of empty static block -- scanning backwards the first one + bit is the second bit of the block, if the last byte is zero, then + we know the byte before that has a one in the top bit, since an + empty static block is ten bits long */ + if ((log->first = lseek(log->fd, -1, SEEK_CUR)) < 0 || + read(log->fd, buf, 1) != 1) + return -1; + log->first++; + if (*buf) { + log->back = 1; + while ((*buf & ((uint)1 << (8 - log->back++))) == 0) + ; /* guaranteed to terminate, since *buf != 0 */ + } + else + log->back = 10; + + /* update compressed crc and length */ + log->ccrc = log->tcrc; + log->clen = log->tlen; + } + else { + /* no data to compress -- fix up existing gzip stream */ + log->tcrc = log->ccrc; + log->tlen = log->clen; + } + + /* complete and truncate gzip stream */ + log->last = log->first; + log->stored = 0; + PUT4(buf, log->tcrc); + PUT4(buf + 4, log->tlen); + if (log_last(log, 1) || write(log->fd, buf, 8) != 8 || + (end = lseek(log->fd, 0, SEEK_CUR)) < 0 || ftruncate(log->fd, end)) + return -1; + BAIL(6); + + /* mark as being in the replace operation */ + if (log_mark(log, REPLACE_OP)) + return -1; + + /* execute the replace operation and mark the file as done */ + return log_replace(log); +} + +/* log a repair record to the .repairs file */ +local void log_log(struct log *log, int op, char *record) +{ + time_t now; + FILE *rec; + + now = time(NULL); + strcpy(log->end, ".repairs"); + rec = fopen(log->path, "a"); + if (rec == NULL) + return; + fprintf(rec, "%.24s %s recovery: %s\n", ctime(&now), op == APPEND_OP ? + "append" : (op == COMPRESS_OP ? "compress" : "replace"), record); + fclose(rec); + return; +} + +/* Recover the interrupted operation op. First read foo.add for recovering an + append or compress operation. Return -1 if there was an error reading or + writing foo.gz or reading an existing foo.add, or -2 if there was a memory + allocation failure. */ +local int log_recover(struct log *log, int op) +{ + int fd, ret = 0; + unsigned char *data = NULL; + size_t len = 0; + struct stat st; + + /* log recovery */ + log_log(log, op, "start"); + + /* load foo.add file if expected and present */ + if (op == APPEND_OP || op == COMPRESS_OP) { + strcpy(log->end, ".add"); + if (stat(log->path, &st) == 0 && st.st_size) { + len = (size_t)(st.st_size); + if ((off_t)len != st.st_size || + (data = malloc(st.st_size)) == NULL) { + log_log(log, op, "allocation failure"); + return -2; + } + if ((fd = open(log->path, O_RDONLY, 0)) < 0) { + log_log(log, op, ".add file read failure"); + return -1; + } + ret = (size_t)read(fd, data, len) != len; + close(fd); + if (ret) { + log_log(log, op, ".add file read failure"); + return -1; + } + log_log(log, op, "loaded .add file"); + } + else + log_log(log, op, "missing .add file!"); + } + + /* recover the interrupted operation */ + switch (op) { + case APPEND_OP: + ret = log_append(log, data, len); + break; + case COMPRESS_OP: + ret = log_compress(log, data, len); + break; + case REPLACE_OP: + ret = log_replace(log); + } + + /* log status */ + log_log(log, op, ret ? "failure" : "complete"); + + /* clean up */ + if (data != NULL) + free(data); + return ret; +} + +/* Close the foo.gz file (if open) and release the lock. */ +local void log_close(struct log *log) +{ + if (log->fd >= 0) + close(log->fd); + log->fd = -1; + log_unlock(log); +} + +/* Open foo.gz, verify the header, and load the extra field contents, after + first creating the foo.lock file to gain exclusive access to the foo.* + files. If foo.gz does not exist or is empty, then write the initial header, + extra, and body content of an empty foo.gz log file. If there is an error + creating the lock file due to access restrictions, or an error reading or + writing the foo.gz file, or if the foo.gz file is not a proper log file for + this object (e.g. not a gzip file or does not contain the expected extra + field), then return true. If there is an error, the lock is released. + Otherwise, the lock is left in place. */ +local int log_open(struct log *log) +{ + int op; + + /* release open file resource if left over -- can occur if lock lost + between gzlog_open() and gzlog_write() */ + if (log->fd >= 0) + close(log->fd); + log->fd = -1; + + /* negotiate exclusive access */ + if (log_lock(log) < 0) + return -1; + + /* open the log file, foo.gz */ + strcpy(log->end, ".gz"); + log->fd = open(log->path, O_RDWR | O_CREAT, 0644); + if (log->fd < 0) { + log_close(log); + return -1; + } + + /* if new, initialize foo.gz with an empty log, delete old dictionary */ + if (lseek(log->fd, 0, SEEK_END) == 0) { + if (write(log->fd, log_gzhead, HEAD) != HEAD || + write(log->fd, log_gzext, EXTRA) != EXTRA || + write(log->fd, log_gzbody, BODY) != BODY) { + log_close(log); + return -1; + } + strcpy(log->end, ".dict"); + unlink(log->path); + } + + /* verify log file and load extra field information */ + if ((op = log_head(log)) < 0) { + log_close(log); + return -1; + } + + /* check for interrupted process and if so, recover */ + if (op != NO_OP && log_recover(log, op)) { + log_close(log); + return -1; + } + + /* touch the lock file to prevent another process from grabbing it */ + log_touch(log); + return 0; +} + +/* See gzlog.h for the description of the external methods below */ +gzlog *gzlog_open(char *path) +{ + size_t n; + struct log *log; + + /* check arguments */ + if (path == NULL || *path == 0) + return NULL; + + /* allocate and initialize log structure */ + log = malloc(sizeof(struct log)); + if (log == NULL) + return NULL; + strcpy(log->id, LOGID); + log->fd = -1; + + /* save path and end of path for name construction */ + n = strlen(path); + log->path = malloc(n + 9); /* allow for ".repairs" */ + if (log->path == NULL) { + free(log); + return NULL; + } + strcpy(log->path, path); + log->end = log->path + n; + + /* gain exclusive access and verify log file -- may perform a + recovery operation if needed */ + if (log_open(log)) { + free(log->path); + free(log); + return NULL; + } + + /* return pointer to log structure */ + return log; +} + +/* gzlog_compress() return values: + 0: all good + -1: file i/o error (usually access issue) + -2: memory allocation failure + -3: invalid log pointer argument */ +int gzlog_compress(gzlog *logd) +{ + int fd, ret; + uint block; + size_t len, next; + unsigned char *data, buf[5]; + struct log *log = logd; + + /* check arguments */ + if (log == NULL || strcmp(log->id, LOGID)) + return -3; + + /* see if we lost the lock -- if so get it again and reload the extra + field information (it probably changed), recover last operation if + necessary */ + if (log_check(log) && log_open(log)) + return -1; + + /* create space for uncompressed data */ + len = ((size_t)(log->last - log->first) & ~(((size_t)1 << 10) - 1)) + + log->stored; + if ((data = malloc(len)) == NULL) + return -2; + + /* do statement here is just a cheap trick for error handling */ + do { + /* read in the uncompressed data */ + if (lseek(log->fd, log->first - 1, SEEK_SET) < 0) + break; + next = 0; + while (next < len) { + if (read(log->fd, buf, 5) != 5) + break; + block = PULL2(buf + 1); + if (next + block > len || + read(log->fd, (char *)data + next, block) != block) + break; + next += block; + } + if (lseek(log->fd, 0, SEEK_CUR) != log->last + 4 + log->stored) + break; + log_touch(log); + + /* write the uncompressed data to the .add file */ + strcpy(log->end, ".add"); + fd = open(log->path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) + break; + ret = (size_t)write(fd, data, len) != len; + if (ret | close(fd)) + break; + log_touch(log); + + /* write the dictionary for the next compress to the .temp file */ + strcpy(log->end, ".temp"); + fd = open(log->path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) + break; + next = DICT > len ? len : DICT; + ret = (size_t)write(fd, (char *)data + len - next, next) != next; + if (ret | close(fd)) + break; + log_touch(log); + + /* roll back to compressed data, mark the compress in progress */ + log->last = log->first; + log->stored = 0; + if (log_mark(log, COMPRESS_OP)) + break; + BAIL(7); + + /* compress and append the data (clears mark) */ + ret = log_compress(log, data, len); + free(data); + return ret; + } while (0); + + /* broke out of do above on i/o error */ + free(data); + return -1; +} + +/* gzlog_write() return values: + 0: all good + -1: file i/o error (usually access issue) + -2: memory allocation failure + -3: invalid log pointer argument */ +int gzlog_write(gzlog *logd, void *data, size_t len) +{ + int fd, ret; + struct log *log = logd; + + /* check arguments */ + if (log == NULL || strcmp(log->id, LOGID)) + return -3; + if (data == NULL || len <= 0) + return 0; + + /* see if we lost the lock -- if so get it again and reload the extra + field information (it probably changed), recover last operation if + necessary */ + if (log_check(log) && log_open(log)) + return -1; + + /* create and write .add file */ + strcpy(log->end, ".add"); + fd = open(log->path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) + return -1; + ret = (size_t)write(fd, data, len) != len; + if (ret | close(fd)) + return -1; + log_touch(log); + + /* mark log file with append in progress */ + if (log_mark(log, APPEND_OP)) + return -1; + BAIL(8); + + /* append data (clears mark) */ + if (log_append(log, data, len)) + return -1; + + /* check to see if it's time to compress -- if not, then done */ + if (((log->last - log->first) >> 10) + (log->stored >> 10) < TRIGGER) + return 0; + + /* time to compress */ + return gzlog_compress(log); +} + +/* gzlog_close() return values: + 0: ok + -3: invalid log pointer argument */ +int gzlog_close(gzlog *logd) +{ + struct log *log = logd; + + /* check arguments */ + if (log == NULL || strcmp(log->id, LOGID)) + return -3; + + /* close the log file and release the lock */ + log_close(log); + + /* free structure and return */ + if (log->path != NULL) + free(log->path); + strcpy(log->id, "bad"); + free(log); + return 0; +} diff --git a/test/zlib/zlib-1.2.8/examples/gzlog.h b/test/zlib/zlib-1.2.8/examples/gzlog.h new file mode 100644 index 000000000..86f0cecba --- /dev/null +++ b/test/zlib/zlib-1.2.8/examples/gzlog.h @@ -0,0 +1,91 @@ +/* gzlog.h + Copyright (C) 2004, 2008, 2012 Mark Adler, all rights reserved + version 2.2, 14 Aug 2012 + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler madler@alumni.caltech.edu + */ + +/* Version History: + 1.0 26 Nov 2004 First version + 2.0 25 Apr 2008 Complete redesign for recovery of interrupted operations + Interface changed slightly in that now path is a prefix + Compression now occurs as needed during gzlog_write() + gzlog_write() now always leaves the log file as valid gzip + 2.1 8 Jul 2012 Fix argument checks in gzlog_compress() and gzlog_write() + 2.2 14 Aug 2012 Clean up signed comparisons + */ + +/* + The gzlog object allows writing short messages to a gzipped log file, + opening the log file locked for small bursts, and then closing it. The log + object works by appending stored (uncompressed) data to the gzip file until + 1 MB has been accumulated. At that time, the stored data is compressed, and + replaces the uncompressed data in the file. The log file is truncated to + its new size at that time. After each write operation, the log file is a + valid gzip file that can decompressed to recover what was written. + + The gzlog operations can be interupted at any point due to an application or + system crash, and the log file will be recovered the next time the log is + opened with gzlog_open(). + */ + +#ifndef GZLOG_H +#define GZLOG_H + +/* gzlog object type */ +typedef void gzlog; + +/* Open a gzlog object, creating the log file if it does not exist. Return + NULL on error. Note that gzlog_open() could take a while to complete if it + has to wait to verify that a lock is stale (possibly for five minutes), or + if there is significant contention with other instantiations of this object + when locking the resource. path is the prefix of the file names created by + this object. If path is "foo", then the log file will be "foo.gz", and + other auxiliary files will be created and destroyed during the process: + "foo.dict" for a compression dictionary, "foo.temp" for a temporary (next) + dictionary, "foo.add" for data being added or compressed, "foo.lock" for the + lock file, and "foo.repairs" to log recovery operations performed due to + interrupted gzlog operations. A gzlog_open() followed by a gzlog_close() + will recover a previously interrupted operation, if any. */ +gzlog *gzlog_open(char *path); + +/* Write to a gzlog object. Return zero on success, -1 if there is a file i/o + error on any of the gzlog files (this should not happen if gzlog_open() + succeeded, unless the device has run out of space or leftover auxiliary + files have permissions or ownership that prevent their use), -2 if there is + a memory allocation failure, or -3 if the log argument is invalid (e.g. if + it was not created by gzlog_open()). This function will write data to the + file uncompressed, until 1 MB has been accumulated, at which time that data + will be compressed. The log file will be a valid gzip file upon successful + return. */ +int gzlog_write(gzlog *log, void *data, size_t len); + +/* Force compression of any uncompressed data in the log. This should be used + sparingly, if at all. The main application would be when a log file will + not be appended to again. If this is used to compress frequently while + appending, it will both significantly increase the execution time and + reduce the compression ratio. The return codes are the same as for + gzlog_write(). */ +int gzlog_compress(gzlog *log); + +/* Close a gzlog object. Return zero on success, -3 if the log argument is + invalid. The log object is freed, and so cannot be referenced again. */ +int gzlog_close(gzlog *log); + +#endif diff --git a/test/zlib/zlib-1.2.8/examples/zlib_how.html b/test/zlib/zlib-1.2.8/examples/zlib_how.html new file mode 100644 index 000000000..444ff1c9a --- /dev/null +++ b/test/zlib/zlib-1.2.8/examples/zlib_how.html @@ -0,0 +1,545 @@ + + + + +zlib Usage Example + + + +

    zlib Usage Example

    +We often get questions about how the deflate() and inflate() functions should be used. +Users wonder when they should provide more input, when they should use more output, +what to do with a Z_BUF_ERROR, how to make sure the process terminates properly, and +so on. So for those who have read zlib.h (a few times), and +would like further edification, below is an annotated example in C of simple routines to compress and decompress +from an input file to an output file using deflate() and inflate() respectively. The +annotations are interspersed between lines of the code. So please read between the lines. +We hope this helps explain some of the intricacies of zlib. +

    +Without further adieu, here is the program zpipe.c: +

    
    +/* zpipe.c: example of proper use of zlib's inflate() and deflate()
    +   Not copyrighted -- provided to the public domain
    +   Version 1.4  11 December 2005  Mark Adler */
    +
    +/* Version history:
    +   1.0  30 Oct 2004  First version
    +   1.1   8 Nov 2004  Add void casting for unused return values
    +                     Use switch statement for inflate() return values
    +   1.2   9 Nov 2004  Add assertions to document zlib guarantees
    +   1.3   6 Apr 2005  Remove incorrect assertion in inf()
    +   1.4  11 Dec 2005  Add hack to avoid MSDOS end-of-line conversions
    +                     Avoid some compiler warnings for input and output buffers
    + */
    +
    +We now include the header files for the required definitions. From +stdio.h we use fopen(), fread(), fwrite(), +feof(), ferror(), and fclose() for file i/o, and +fputs() for error messages. From string.h we use +strcmp() for command line argument processing. +From assert.h we use the assert() macro. +From zlib.h +we use the basic compression functions deflateInit(), +deflate(), and deflateEnd(), and the basic decompression +functions inflateInit(), inflate(), and +inflateEnd(). +
    
    +#include <stdio.h>
    +#include <string.h>
    +#include <assert.h>
    +#include "zlib.h"
    +
    +This is an ugly hack required to avoid corruption of the input and output data on +Windows/MS-DOS systems. Without this, those systems would assume that the input and output +files are text, and try to convert the end-of-line characters from one standard to +another. That would corrupt binary data, and in particular would render the compressed data unusable. +This sets the input and output to binary which suppresses the end-of-line conversions. +SET_BINARY_MODE() will be used later on stdin and stdout, at the beginning of main(). +
    
    +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
    +#  include <fcntl.h>
    +#  include <io.h>
    +#  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
    +#else
    +#  define SET_BINARY_MODE(file)
    +#endif
    +
    +CHUNK is simply the buffer size for feeding data to and pulling data +from the zlib routines. Larger buffer sizes would be more efficient, +especially for inflate(). If the memory is available, buffers sizes +on the order of 128K or 256K bytes should be used. +
    
    +#define CHUNK 16384
    +
    +The def() routine compresses data from an input file to an output file. The output data +will be in the zlib format, which is different from the gzip or zip +formats. The zlib format has a very small header of only two bytes to identify it as +a zlib stream and to provide decoding information, and a four-byte trailer with a fast +check value to verify the integrity of the uncompressed data after decoding. +
    
    +/* Compress from file source to file dest until EOF on source.
    +   def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
    +   allocated for processing, Z_STREAM_ERROR if an invalid compression
    +   level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
    +   version of the library linked do not match, or Z_ERRNO if there is
    +   an error reading or writing the files. */
    +int def(FILE *source, FILE *dest, int level)
    +{
    +
    +Here are the local variables for def(). ret will be used for zlib +return codes. flush will keep track of the current flushing state for deflate(), +which is either no flushing, or flush to completion after the end of the input file is reached. +have is the amount of data returned from deflate(). The strm structure +is used to pass information to and from the zlib routines, and to maintain the +deflate() state. in and out are the input and output buffers for +deflate(). +
    
    +    int ret, flush;
    +    unsigned have;
    +    z_stream strm;
    +    unsigned char in[CHUNK];
    +    unsigned char out[CHUNK];
    +
    +The first thing we do is to initialize the zlib state for compression using +deflateInit(). This must be done before the first use of deflate(). +The zalloc, zfree, and opaque fields in the strm +structure must be initialized before calling deflateInit(). Here they are +set to the zlib constant Z_NULL to request that zlib use +the default memory allocation routines. An application may also choose to provide +custom memory allocation routines here. deflateInit() will allocate on the +order of 256K bytes for the internal state. +(See zlib Technical Details.) +

    +deflateInit() is called with a pointer to the structure to be initialized and +the compression level, which is an integer in the range of -1 to 9. Lower compression +levels result in faster execution, but less compression. Higher levels result in +greater compression, but slower execution. The zlib constant Z_DEFAULT_COMPRESSION, +equal to -1, +provides a good compromise between compression and speed and is equivalent to level 6. +Level 0 actually does no compression at all, and in fact expands the data slightly to produce +the zlib format (it is not a byte-for-byte copy of the input). +More advanced applications of zlib +may use deflateInit2() here instead. Such an application may want to reduce how +much memory will be used, at some price in compression. Or it may need to request a +gzip header and trailer instead of a zlib header and trailer, or raw +encoding with no header or trailer at all. +

    +We must check the return value of deflateInit() against the zlib constant +Z_OK to make sure that it was able to +allocate memory for the internal state, and that the provided arguments were valid. +deflateInit() will also check that the version of zlib that the zlib.h +file came from matches the version of zlib actually linked with the program. This +is especially important for environments in which zlib is a shared library. +

    +Note that an application can initialize multiple, independent zlib streams, which can +operate in parallel. The state information maintained in the structure allows the zlib +routines to be reentrant. +

    
    +    /* allocate deflate state */
    +    strm.zalloc = Z_NULL;
    +    strm.zfree = Z_NULL;
    +    strm.opaque = Z_NULL;
    +    ret = deflateInit(&strm, level);
    +    if (ret != Z_OK)
    +        return ret;
    +
    +With the pleasantries out of the way, now we can get down to business. The outer do-loop +reads all of the input file and exits at the bottom of the loop once end-of-file is reached. +This loop contains the only call of deflate(). So we must make sure that all of the +input data has been processed and that all of the output data has been generated and consumed +before we fall out of the loop at the bottom. +
    
    +    /* compress until end of file */
    +    do {
    +
    +We start off by reading data from the input file. The number of bytes read is put directly +into avail_in, and a pointer to those bytes is put into next_in. We also +check to see if end-of-file on the input has been reached. If we are at the end of file, then flush is set to the +zlib constant Z_FINISH, which is later passed to deflate() to +indicate that this is the last chunk of input data to compress. We need to use feof() +to check for end-of-file as opposed to seeing if fewer than CHUNK bytes have been read. The +reason is that if the input file length is an exact multiple of CHUNK, we will miss +the fact that we got to the end-of-file, and not know to tell deflate() to finish +up the compressed stream. If we are not yet at the end of the input, then the zlib +constant Z_NO_FLUSH will be passed to deflate to indicate that we are still +in the middle of the uncompressed data. +

    +If there is an error in reading from the input file, the process is aborted with +deflateEnd() being called to free the allocated zlib state before returning +the error. We wouldn't want a memory leak, now would we? deflateEnd() can be called +at any time after the state has been initialized. Once that's done, deflateInit() (or +deflateInit2()) would have to be called to start a new compression process. There is +no point here in checking the deflateEnd() return code. The deallocation can't fail. +

    
    +        strm.avail_in = fread(in, 1, CHUNK, source);
    +        if (ferror(source)) {
    +            (void)deflateEnd(&strm);
    +            return Z_ERRNO;
    +        }
    +        flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
    +        strm.next_in = in;
    +
    +The inner do-loop passes our chunk of input data to deflate(), and then +keeps calling deflate() until it is done producing output. Once there is no more +new output, deflate() is guaranteed to have consumed all of the input, i.e., +avail_in will be zero. +
    
    +        /* run deflate() on input until output buffer not full, finish
    +           compression if all of source has been read in */
    +        do {
    +
    +Output space is provided to deflate() by setting avail_out to the number +of available output bytes and next_out to a pointer to that space. +
    
    +            strm.avail_out = CHUNK;
    +            strm.next_out = out;
    +
    +Now we call the compression engine itself, deflate(). It takes as many of the +avail_in bytes at next_in as it can process, and writes as many as +avail_out bytes to next_out. Those counters and pointers are then +updated past the input data consumed and the output data written. It is the amount of +output space available that may limit how much input is consumed. +Hence the inner loop to make sure that +all of the input is consumed by providing more output space each time. Since avail_in +and next_in are updated by deflate(), we don't have to mess with those +between deflate() calls until it's all used up. +

    +The parameters to deflate() are a pointer to the strm structure containing +the input and output information and the internal compression engine state, and a parameter +indicating whether and how to flush data to the output. Normally deflate will consume +several K bytes of input data before producing any output (except for the header), in order +to accumulate statistics on the data for optimum compression. It will then put out a burst of +compressed data, and proceed to consume more input before the next burst. Eventually, +deflate() +must be told to terminate the stream, complete the compression with provided input data, and +write out the trailer check value. deflate() will continue to compress normally as long +as the flush parameter is Z_NO_FLUSH. Once the Z_FINISH parameter is provided, +deflate() will begin to complete the compressed output stream. However depending on how +much output space is provided, deflate() may have to be called several times until it +has provided the complete compressed stream, even after it has consumed all of the input. The flush +parameter must continue to be Z_FINISH for those subsequent calls. +

    +There are other values of the flush parameter that are used in more advanced applications. You can +force deflate() to produce a burst of output that encodes all of the input data provided +so far, even if it wouldn't have otherwise, for example to control data latency on a link with +compressed data. You can also ask that deflate() do that as well as erase any history up to +that point so that what follows can be decompressed independently, for example for random access +applications. Both requests will degrade compression by an amount depending on how often such +requests are made. +

    +deflate() has a return value that can indicate errors, yet we do not check it here. Why +not? Well, it turns out that deflate() can do no wrong here. Let's go through +deflate()'s return values and dispense with them one by one. The possible values are +Z_OK, Z_STREAM_END, Z_STREAM_ERROR, or Z_BUF_ERROR. Z_OK +is, well, ok. Z_STREAM_END is also ok and will be returned for the last call of +deflate(). This is already guaranteed by calling deflate() with Z_FINISH +until it has no more output. Z_STREAM_ERROR is only possible if the stream is not +initialized properly, but we did initialize it properly. There is no harm in checking for +Z_STREAM_ERROR here, for example to check for the possibility that some +other part of the application inadvertently clobbered the memory containing the zlib state. +Z_BUF_ERROR will be explained further below, but +suffice it to say that this is simply an indication that deflate() could not consume +more input or produce more output. deflate() can be called again with more output space +or more available input, which it will be in this code. +

    
    +            ret = deflate(&strm, flush);    /* no bad return value */
    +            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
    +
    +Now we compute how much output deflate() provided on the last call, which is the +difference between how much space was provided before the call, and how much output space +is still available after the call. Then that data, if any, is written to the output file. +We can then reuse the output buffer for the next call of deflate(). Again if there +is a file i/o error, we call deflateEnd() before returning to avoid a memory leak. +
    
    +            have = CHUNK - strm.avail_out;
    +            if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
    +                (void)deflateEnd(&strm);
    +                return Z_ERRNO;
    +            }
    +
    +The inner do-loop is repeated until the last deflate() call fails to fill the +provided output buffer. Then we know that deflate() has done as much as it can with +the provided input, and that all of that input has been consumed. We can then fall out of this +loop and reuse the input buffer. +

    +The way we tell that deflate() has no more output is by seeing that it did not fill +the output buffer, leaving avail_out greater than zero. However suppose that +deflate() has no more output, but just so happened to exactly fill the output buffer! +avail_out is zero, and we can't tell that deflate() has done all it can. +As far as we know, deflate() +has more output for us. So we call it again. But now deflate() produces no output +at all, and avail_out remains unchanged as CHUNK. That deflate() call +wasn't able to do anything, either consume input or produce output, and so it returns +Z_BUF_ERROR. (See, I told you I'd cover this later.) However this is not a problem at +all. Now we finally have the desired indication that deflate() is really done, +and so we drop out of the inner loop to provide more input to deflate(). +

    +With flush set to Z_FINISH, this final set of deflate() calls will +complete the output stream. Once that is done, subsequent calls of deflate() would return +Z_STREAM_ERROR if the flush parameter is not Z_FINISH, and do no more processing +until the state is reinitialized. +

    +Some applications of zlib have two loops that call deflate() +instead of the single inner loop we have here. The first loop would call +without flushing and feed all of the data to deflate(). The second loop would call +deflate() with no more +data and the Z_FINISH parameter to complete the process. As you can see from this +example, that can be avoided by simply keeping track of the current flush state. +

    
    +        } while (strm.avail_out == 0);
    +        assert(strm.avail_in == 0);     /* all input will be used */
    +
    +Now we check to see if we have already processed all of the input file. That information was +saved in the flush variable, so we see if that was set to Z_FINISH. If so, +then we're done and we fall out of the outer loop. We're guaranteed to get Z_STREAM_END +from the last deflate() call, since we ran it until the last chunk of input was +consumed and all of the output was generated. +
    
    +        /* done when last data in file processed */
    +    } while (flush != Z_FINISH);
    +    assert(ret == Z_STREAM_END);        /* stream will be complete */
    +
    +The process is complete, but we still need to deallocate the state to avoid a memory leak +(or rather more like a memory hemorrhage if you didn't do this). Then +finally we can return with a happy return value. +
    
    +    /* clean up and return */
    +    (void)deflateEnd(&strm);
    +    return Z_OK;
    +}
    +
    +Now we do the same thing for decompression in the inf() routine. inf() +decompresses what is hopefully a valid zlib stream from the input file and writes the +uncompressed data to the output file. Much of the discussion above for def() +applies to inf() as well, so the discussion here will focus on the differences between +the two. +
    
    +/* Decompress from file source to file dest until stream ends or EOF.
    +   inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
    +   allocated for processing, Z_DATA_ERROR if the deflate data is
    +   invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
    +   the version of the library linked do not match, or Z_ERRNO if there
    +   is an error reading or writing the files. */
    +int inf(FILE *source, FILE *dest)
    +{
    +
    +The local variables have the same functionality as they do for def(). The +only difference is that there is no flush variable, since inflate() +can tell from the zlib stream itself when the stream is complete. +
    
    +    int ret;
    +    unsigned have;
    +    z_stream strm;
    +    unsigned char in[CHUNK];
    +    unsigned char out[CHUNK];
    +
    +The initialization of the state is the same, except that there is no compression level, +of course, and two more elements of the structure are initialized. avail_in +and next_in must be initialized before calling inflateInit(). This +is because the application has the option to provide the start of the zlib stream in +order for inflateInit() to have access to information about the compression +method to aid in memory allocation. In the current implementation of zlib +(up through versions 1.2.x), the method-dependent memory allocations are deferred to the first call of +inflate() anyway. However those fields must be initialized since later versions +of zlib that provide more compression methods may take advantage of this interface. +In any case, no decompression is performed by inflateInit(), so the +avail_out and next_out fields do not need to be initialized before calling. +

    +Here avail_in is set to zero and next_in is set to Z_NULL to +indicate that no input data is being provided. +

    
    +    /* allocate inflate state */
    +    strm.zalloc = Z_NULL;
    +    strm.zfree = Z_NULL;
    +    strm.opaque = Z_NULL;
    +    strm.avail_in = 0;
    +    strm.next_in = Z_NULL;
    +    ret = inflateInit(&strm);
    +    if (ret != Z_OK)
    +        return ret;
    +
    +The outer do-loop decompresses input until inflate() indicates +that it has reached the end of the compressed data and has produced all of the uncompressed +output. This is in contrast to def() which processes all of the input file. +If end-of-file is reached before the compressed data self-terminates, then the compressed +data is incomplete and an error is returned. +
    
    +    /* decompress until deflate stream ends or end of file */
    +    do {
    +
    +We read input data and set the strm structure accordingly. If we've reached the +end of the input file, then we leave the outer loop and report an error, since the +compressed data is incomplete. Note that we may read more data than is eventually consumed +by inflate(), if the input file continues past the zlib stream. +For applications where zlib streams are embedded in other data, this routine would +need to be modified to return the unused data, or at least indicate how much of the input +data was not used, so the application would know where to pick up after the zlib stream. +
    
    +        strm.avail_in = fread(in, 1, CHUNK, source);
    +        if (ferror(source)) {
    +            (void)inflateEnd(&strm);
    +            return Z_ERRNO;
    +        }
    +        if (strm.avail_in == 0)
    +            break;
    +        strm.next_in = in;
    +
    +The inner do-loop has the same function it did in def(), which is to +keep calling inflate() until has generated all of the output it can with the +provided input. +
    
    +        /* run inflate() on input until output buffer not full */
    +        do {
    +
    +Just like in def(), the same output space is provided for each call of inflate(). +
    
    +            strm.avail_out = CHUNK;
    +            strm.next_out = out;
    +
    +Now we run the decompression engine itself. There is no need to adjust the flush parameter, since +the zlib format is self-terminating. The main difference here is that there are +return values that we need to pay attention to. Z_DATA_ERROR +indicates that inflate() detected an error in the zlib compressed data format, +which means that either the data is not a zlib stream to begin with, or that the data was +corrupted somewhere along the way since it was compressed. The other error to be processed is +Z_MEM_ERROR, which can occur since memory allocation is deferred until inflate() +needs it, unlike deflate(), whose memory is allocated at the start by deflateInit(). +

    +Advanced applications may use +deflateSetDictionary() to prime deflate() with a set of likely data to improve the +first 32K or so of compression. This is noted in the zlib header, so inflate() +requests that that dictionary be provided before it can start to decompress. Without the dictionary, +correct decompression is not possible. For this routine, we have no idea what the dictionary is, +so the Z_NEED_DICT indication is converted to a Z_DATA_ERROR. +

    +inflate() can also return Z_STREAM_ERROR, which should not be possible here, +but could be checked for as noted above for def(). Z_BUF_ERROR does not need to be +checked for here, for the same reasons noted for def(). Z_STREAM_END will be +checked for later. +

    
    +            ret = inflate(&strm, Z_NO_FLUSH);
    +            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
    +            switch (ret) {
    +            case Z_NEED_DICT:
    +                ret = Z_DATA_ERROR;     /* and fall through */
    +            case Z_DATA_ERROR:
    +            case Z_MEM_ERROR:
    +                (void)inflateEnd(&strm);
    +                return ret;
    +            }
    +
    +The output of inflate() is handled identically to that of deflate(). +
    
    +            have = CHUNK - strm.avail_out;
    +            if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
    +                (void)inflateEnd(&strm);
    +                return Z_ERRNO;
    +            }
    +
    +The inner do-loop ends when inflate() has no more output as indicated +by not filling the output buffer, just as for deflate(). In this case, we cannot +assert that strm.avail_in will be zero, since the deflate stream may end before the file +does. +
    
    +        } while (strm.avail_out == 0);
    +
    +The outer do-loop ends when inflate() reports that it has reached the +end of the input zlib stream, has completed the decompression and integrity +check, and has provided all of the output. This is indicated by the inflate() +return value Z_STREAM_END. The inner loop is guaranteed to leave ret +equal to Z_STREAM_END if the last chunk of the input file read contained the end +of the zlib stream. So if the return value is not Z_STREAM_END, the +loop continues to read more input. +
    
    +        /* done when inflate() says it's done */
    +    } while (ret != Z_STREAM_END);
    +
    +At this point, decompression successfully completed, or we broke out of the loop due to no +more data being available from the input file. If the last inflate() return value +is not Z_STREAM_END, then the zlib stream was incomplete and a data error +is returned. Otherwise, we return with a happy return value. Of course, inflateEnd() +is called first to avoid a memory leak. +
    
    +    /* clean up and return */
    +    (void)inflateEnd(&strm);
    +    return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
    +}
    +
    +That ends the routines that directly use zlib. The following routines make this +a command-line program by running data through the above routines from stdin to +stdout, and handling any errors reported by def() or inf(). +

    +zerr() is used to interpret the possible error codes from def() +and inf(), as detailed in their comments above, and print out an error message. +Note that these are only a subset of the possible return values from deflate() +and inflate(). +

    
    +/* report a zlib or i/o error */
    +void zerr(int ret)
    +{
    +    fputs("zpipe: ", stderr);
    +    switch (ret) {
    +    case Z_ERRNO:
    +        if (ferror(stdin))
    +            fputs("error reading stdin\n", stderr);
    +        if (ferror(stdout))
    +            fputs("error writing stdout\n", stderr);
    +        break;
    +    case Z_STREAM_ERROR:
    +        fputs("invalid compression level\n", stderr);
    +        break;
    +    case Z_DATA_ERROR:
    +        fputs("invalid or incomplete deflate data\n", stderr);
    +        break;
    +    case Z_MEM_ERROR:
    +        fputs("out of memory\n", stderr);
    +        break;
    +    case Z_VERSION_ERROR:
    +        fputs("zlib version mismatch!\n", stderr);
    +    }
    +}
    +
    +Here is the main() routine used to test def() and inf(). The +zpipe command is simply a compression pipe from stdin to stdout, if +no arguments are given, or it is a decompression pipe if zpipe -d is used. If any other +arguments are provided, no compression or decompression is performed. Instead a usage +message is displayed. Examples are zpipe < foo.txt > foo.txt.z to compress, and +zpipe -d < foo.txt.z > foo.txt to decompress. +
    
    +/* compress or decompress from stdin to stdout */
    +int main(int argc, char **argv)
    +{
    +    int ret;
    +
    +    /* avoid end-of-line conversions */
    +    SET_BINARY_MODE(stdin);
    +    SET_BINARY_MODE(stdout);
    +
    +    /* do compression if no arguments */
    +    if (argc == 1) {
    +        ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION);
    +        if (ret != Z_OK)
    +            zerr(ret);
    +        return ret;
    +    }
    +
    +    /* do decompression if -d specified */
    +    else if (argc == 2 && strcmp(argv[1], "-d") == 0) {
    +        ret = inf(stdin, stdout);
    +        if (ret != Z_OK)
    +            zerr(ret);
    +        return ret;
    +    }
    +
    +    /* otherwise, report usage */
    +    else {
    +        fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr);
    +        return 1;
    +    }
    +}
    +
    +
    +Copyright (c) 2004, 2005 by Mark Adler
    Last modified 11 December 2005
    + + diff --git a/test/zlib/zlib-1.2.8/examples/zpipe.c b/test/zlib/zlib-1.2.8/examples/zpipe.c new file mode 100644 index 000000000..83535d169 --- /dev/null +++ b/test/zlib/zlib-1.2.8/examples/zpipe.c @@ -0,0 +1,205 @@ +/* zpipe.c: example of proper use of zlib's inflate() and deflate() + Not copyrighted -- provided to the public domain + Version 1.4 11 December 2005 Mark Adler */ + +/* Version history: + 1.0 30 Oct 2004 First version + 1.1 8 Nov 2004 Add void casting for unused return values + Use switch statement for inflate() return values + 1.2 9 Nov 2004 Add assertions to document zlib guarantees + 1.3 6 Apr 2005 Remove incorrect assertion in inf() + 1.4 11 Dec 2005 Add hack to avoid MSDOS end-of-line conversions + Avoid some compiler warnings for input and output buffers + */ + +#include +#include +#include +#include "zlib.h" + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include +# include +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#define CHUNK 16384 + +/* Compress from file source to file dest until EOF on source. + def() returns Z_OK on success, Z_MEM_ERROR if memory could not be + allocated for processing, Z_STREAM_ERROR if an invalid compression + level is supplied, Z_VERSION_ERROR if the version of zlib.h and the + version of the library linked do not match, or Z_ERRNO if there is + an error reading or writing the files. */ +int def(FILE *source, FILE *dest, int level) +{ + int ret, flush; + unsigned have; + z_stream strm; + unsigned char in[CHUNK]; + unsigned char out[CHUNK]; + + /* allocate deflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + ret = deflateInit(&strm, level); + if (ret != Z_OK) + return ret; + + /* compress until end of file */ + do { + strm.avail_in = fread(in, 1, CHUNK, source); + if (ferror(source)) { + (void)deflateEnd(&strm); + return Z_ERRNO; + } + flush = feof(source) ? Z_FINISH : Z_NO_FLUSH; + strm.next_in = in; + + /* run deflate() on input until output buffer not full, finish + compression if all of source has been read in */ + do { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = deflate(&strm, flush); /* no bad return value */ + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + have = CHUNK - strm.avail_out; + if (fwrite(out, 1, have, dest) != have || ferror(dest)) { + (void)deflateEnd(&strm); + return Z_ERRNO; + } + } while (strm.avail_out == 0); + assert(strm.avail_in == 0); /* all input will be used */ + + /* done when last data in file processed */ + } while (flush != Z_FINISH); + assert(ret == Z_STREAM_END); /* stream will be complete */ + + /* clean up and return */ + (void)deflateEnd(&strm); + return Z_OK; +} + +/* Decompress from file source to file dest until stream ends or EOF. + inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be + allocated for processing, Z_DATA_ERROR if the deflate data is + invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and + the version of the library linked do not match, or Z_ERRNO if there + is an error reading or writing the files. */ +int inf(FILE *source, FILE *dest) +{ + int ret; + unsigned have; + z_stream strm; + unsigned char in[CHUNK]; + unsigned char out[CHUNK]; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); + if (ret != Z_OK) + return ret; + + /* decompress until deflate stream ends or end of file */ + do { + strm.avail_in = fread(in, 1, CHUNK, source); + if (ferror(source)) { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + if (strm.avail_in == 0) + break; + strm.next_in = in; + + /* run inflate() on input until output buffer not full */ + do { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return ret; + } + have = CHUNK - strm.avail_out; + if (fwrite(out, 1, have, dest) != have || ferror(dest)) { + (void)inflateEnd(&strm); + return Z_ERRNO; + } + } while (strm.avail_out == 0); + + /* done when inflate() says it's done */ + } while (ret != Z_STREAM_END); + + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; +} + +/* report a zlib or i/o error */ +void zerr(int ret) +{ + fputs("zpipe: ", stderr); + switch (ret) { + case Z_ERRNO: + if (ferror(stdin)) + fputs("error reading stdin\n", stderr); + if (ferror(stdout)) + fputs("error writing stdout\n", stderr); + break; + case Z_STREAM_ERROR: + fputs("invalid compression level\n", stderr); + break; + case Z_DATA_ERROR: + fputs("invalid or incomplete deflate data\n", stderr); + break; + case Z_MEM_ERROR: + fputs("out of memory\n", stderr); + break; + case Z_VERSION_ERROR: + fputs("zlib version mismatch!\n", stderr); + } +} + +/* compress or decompress from stdin to stdout */ +int main(int argc, char **argv) +{ + int ret; + + /* avoid end-of-line conversions */ + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + + /* do compression if no arguments */ + if (argc == 1) { + ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION); + if (ret != Z_OK) + zerr(ret); + return ret; + } + + /* do decompression if -d specified */ + else if (argc == 2 && strcmp(argv[1], "-d") == 0) { + ret = inf(stdin, stdout); + if (ret != Z_OK) + zerr(ret); + return ret; + } + + /* otherwise, report usage */ + else { + fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr); + return 1; + } +} diff --git a/test/zlib/zlib-1.2.8/examples/zran.c b/test/zlib/zlib-1.2.8/examples/zran.c new file mode 100644 index 000000000..278f9ad07 --- /dev/null +++ b/test/zlib/zlib-1.2.8/examples/zran.c @@ -0,0 +1,409 @@ +/* zran.c -- example of zlib/gzip stream indexing and random access + * Copyright (C) 2005, 2012 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + Version 1.1 29 Sep 2012 Mark Adler */ + +/* Version History: + 1.0 29 May 2005 First version + 1.1 29 Sep 2012 Fix memory reallocation error + */ + +/* Illustrate the use of Z_BLOCK, inflatePrime(), and inflateSetDictionary() + for random access of a compressed file. A file containing a zlib or gzip + stream is provided on the command line. The compressed stream is decoded in + its entirety, and an index built with access points about every SPAN bytes + in the uncompressed output. The compressed file is left open, and can then + be read randomly, having to decompress on the average SPAN/2 uncompressed + bytes before getting to the desired block of data. + + An access point can be created at the start of any deflate block, by saving + the starting file offset and bit of that block, and the 32K bytes of + uncompressed data that precede that block. Also the uncompressed offset of + that block is saved to provide a referece for locating a desired starting + point in the uncompressed stream. build_index() works by decompressing the + input zlib or gzip stream a block at a time, and at the end of each block + deciding if enough uncompressed data has gone by to justify the creation of + a new access point. If so, that point is saved in a data structure that + grows as needed to accommodate the points. + + To use the index, an offset in the uncompressed data is provided, for which + the latest accees point at or preceding that offset is located in the index. + The input file is positioned to the specified location in the index, and if + necessary the first few bits of the compressed data is read from the file. + inflate is initialized with those bits and the 32K of uncompressed data, and + the decompression then proceeds until the desired offset in the file is + reached. Then the decompression continues to read the desired uncompressed + data from the file. + + Another approach would be to generate the index on demand. In that case, + requests for random access reads from the compressed data would try to use + the index, but if a read far enough past the end of the index is required, + then further index entries would be generated and added. + + There is some fair bit of overhead to starting inflation for the random + access, mainly copying the 32K byte dictionary. So if small pieces of the + file are being accessed, it would make sense to implement a cache to hold + some lookahead and avoid many calls to extract() for small lengths. + + Another way to build an index would be to use inflateCopy(). That would + not be constrained to have access points at block boundaries, but requires + more memory per access point, and also cannot be saved to file due to the + use of pointers in the state. The approach here allows for storage of the + index in a file. + */ + +#include +#include +#include +#include "zlib.h" + +#define local static + +#define SPAN 1048576L /* desired distance between access points */ +#define WINSIZE 32768U /* sliding window size */ +#define CHUNK 16384 /* file input buffer size */ + +/* access point entry */ +struct point { + off_t out; /* corresponding offset in uncompressed data */ + off_t in; /* offset in input file of first full byte */ + int bits; /* number of bits (1-7) from byte at in - 1, or 0 */ + unsigned char window[WINSIZE]; /* preceding 32K of uncompressed data */ +}; + +/* access point list */ +struct access { + int have; /* number of list entries filled in */ + int size; /* number of list entries allocated */ + struct point *list; /* allocated list */ +}; + +/* Deallocate an index built by build_index() */ +local void free_index(struct access *index) +{ + if (index != NULL) { + free(index->list); + free(index); + } +} + +/* Add an entry to the access point list. If out of memory, deallocate the + existing list and return NULL. */ +local struct access *addpoint(struct access *index, int bits, + off_t in, off_t out, unsigned left, unsigned char *window) +{ + struct point *next; + + /* if list is empty, create it (start with eight points) */ + if (index == NULL) { + index = malloc(sizeof(struct access)); + if (index == NULL) return NULL; + index->list = malloc(sizeof(struct point) << 3); + if (index->list == NULL) { + free(index); + return NULL; + } + index->size = 8; + index->have = 0; + } + + /* if list is full, make it bigger */ + else if (index->have == index->size) { + index->size <<= 1; + next = realloc(index->list, sizeof(struct point) * index->size); + if (next == NULL) { + free_index(index); + return NULL; + } + index->list = next; + } + + /* fill in entry and increment how many we have */ + next = index->list + index->have; + next->bits = bits; + next->in = in; + next->out = out; + if (left) + memcpy(next->window, window + WINSIZE - left, left); + if (left < WINSIZE) + memcpy(next->window + left, window, WINSIZE - left); + index->have++; + + /* return list, possibly reallocated */ + return index; +} + +/* Make one entire pass through the compressed stream and build an index, with + access points about every span bytes of uncompressed output -- span is + chosen to balance the speed of random access against the memory requirements + of the list, about 32K bytes per access point. Note that data after the end + of the first zlib or gzip stream in the file is ignored. build_index() + returns the number of access points on success (>= 1), Z_MEM_ERROR for out + of memory, Z_DATA_ERROR for an error in the input file, or Z_ERRNO for a + file read error. On success, *built points to the resulting index. */ +local int build_index(FILE *in, off_t span, struct access **built) +{ + int ret; + off_t totin, totout; /* our own total counters to avoid 4GB limit */ + off_t last; /* totout value of last access point */ + struct access *index; /* access points being generated */ + z_stream strm; + unsigned char input[CHUNK]; + unsigned char window[WINSIZE]; + + /* initialize inflate */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, 47); /* automatic zlib or gzip decoding */ + if (ret != Z_OK) + return ret; + + /* inflate the input, maintain a sliding window, and build an index -- this + also validates the integrity of the compressed data using the check + information at the end of the gzip or zlib stream */ + totin = totout = last = 0; + index = NULL; /* will be allocated by first addpoint() */ + strm.avail_out = 0; + do { + /* get some compressed data from input file */ + strm.avail_in = fread(input, 1, CHUNK, in); + if (ferror(in)) { + ret = Z_ERRNO; + goto build_index_error; + } + if (strm.avail_in == 0) { + ret = Z_DATA_ERROR; + goto build_index_error; + } + strm.next_in = input; + + /* process all of that, or until end of stream */ + do { + /* reset sliding window if necessary */ + if (strm.avail_out == 0) { + strm.avail_out = WINSIZE; + strm.next_out = window; + } + + /* inflate until out of input, output, or at end of block -- + update the total input and output counters */ + totin += strm.avail_in; + totout += strm.avail_out; + ret = inflate(&strm, Z_BLOCK); /* return at end of block */ + totin -= strm.avail_in; + totout -= strm.avail_out; + if (ret == Z_NEED_DICT) + ret = Z_DATA_ERROR; + if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR) + goto build_index_error; + if (ret == Z_STREAM_END) + break; + + /* if at end of block, consider adding an index entry (note that if + data_type indicates an end-of-block, then all of the + uncompressed data from that block has been delivered, and none + of the compressed data after that block has been consumed, + except for up to seven bits) -- the totout == 0 provides an + entry point after the zlib or gzip header, and assures that the + index always has at least one access point; we avoid creating an + access point after the last block by checking bit 6 of data_type + */ + if ((strm.data_type & 128) && !(strm.data_type & 64) && + (totout == 0 || totout - last > span)) { + index = addpoint(index, strm.data_type & 7, totin, + totout, strm.avail_out, window); + if (index == NULL) { + ret = Z_MEM_ERROR; + goto build_index_error; + } + last = totout; + } + } while (strm.avail_in != 0); + } while (ret != Z_STREAM_END); + + /* clean up and return index (release unused entries in list) */ + (void)inflateEnd(&strm); + index->list = realloc(index->list, sizeof(struct point) * index->have); + index->size = index->have; + *built = index; + return index->size; + + /* return error */ + build_index_error: + (void)inflateEnd(&strm); + if (index != NULL) + free_index(index); + return ret; +} + +/* Use the index to read len bytes from offset into buf, return bytes read or + negative for error (Z_DATA_ERROR or Z_MEM_ERROR). If data is requested past + the end of the uncompressed data, then extract() will return a value less + than len, indicating how much as actually read into buf. This function + should not return a data error unless the file was modified since the index + was generated. extract() may also return Z_ERRNO if there is an error on + reading or seeking the input file. */ +local int extract(FILE *in, struct access *index, off_t offset, + unsigned char *buf, int len) +{ + int ret, skip; + z_stream strm; + struct point *here; + unsigned char input[CHUNK]; + unsigned char discard[WINSIZE]; + + /* proceed only if something reasonable to do */ + if (len < 0) + return 0; + + /* find where in stream to start */ + here = index->list; + ret = index->have; + while (--ret && here[1].out <= offset) + here++; + + /* initialize file and inflate state to start there */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, -15); /* raw inflate */ + if (ret != Z_OK) + return ret; + ret = fseeko(in, here->in - (here->bits ? 1 : 0), SEEK_SET); + if (ret == -1) + goto extract_ret; + if (here->bits) { + ret = getc(in); + if (ret == -1) { + ret = ferror(in) ? Z_ERRNO : Z_DATA_ERROR; + goto extract_ret; + } + (void)inflatePrime(&strm, here->bits, ret >> (8 - here->bits)); + } + (void)inflateSetDictionary(&strm, here->window, WINSIZE); + + /* skip uncompressed bytes until offset reached, then satisfy request */ + offset -= here->out; + strm.avail_in = 0; + skip = 1; /* while skipping to offset */ + do { + /* define where to put uncompressed data, and how much */ + if (offset == 0 && skip) { /* at offset now */ + strm.avail_out = len; + strm.next_out = buf; + skip = 0; /* only do this once */ + } + if (offset > WINSIZE) { /* skip WINSIZE bytes */ + strm.avail_out = WINSIZE; + strm.next_out = discard; + offset -= WINSIZE; + } + else if (offset != 0) { /* last skip */ + strm.avail_out = (unsigned)offset; + strm.next_out = discard; + offset = 0; + } + + /* uncompress until avail_out filled, or end of stream */ + do { + if (strm.avail_in == 0) { + strm.avail_in = fread(input, 1, CHUNK, in); + if (ferror(in)) { + ret = Z_ERRNO; + goto extract_ret; + } + if (strm.avail_in == 0) { + ret = Z_DATA_ERROR; + goto extract_ret; + } + strm.next_in = input; + } + ret = inflate(&strm, Z_NO_FLUSH); /* normal inflate */ + if (ret == Z_NEED_DICT) + ret = Z_DATA_ERROR; + if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR) + goto extract_ret; + if (ret == Z_STREAM_END) + break; + } while (strm.avail_out != 0); + + /* if reach end of stream, then don't keep trying to get more */ + if (ret == Z_STREAM_END) + break; + + /* do until offset reached and requested data read, or stream ends */ + } while (skip); + + /* compute number of uncompressed bytes read after offset */ + ret = skip ? 0 : len - strm.avail_out; + + /* clean up and return bytes read or error */ + extract_ret: + (void)inflateEnd(&strm); + return ret; +} + +/* Demonstrate the use of build_index() and extract() by processing the file + provided on the command line, and the extracting 16K from about 2/3rds of + the way through the uncompressed output, and writing that to stdout. */ +int main(int argc, char **argv) +{ + int len; + off_t offset; + FILE *in; + struct access *index = NULL; + unsigned char buf[CHUNK]; + + /* open input file */ + if (argc != 2) { + fprintf(stderr, "usage: zran file.gz\n"); + return 1; + } + in = fopen(argv[1], "rb"); + if (in == NULL) { + fprintf(stderr, "zran: could not open %s for reading\n", argv[1]); + return 1; + } + + /* build index */ + len = build_index(in, SPAN, &index); + if (len < 0) { + fclose(in); + switch (len) { + case Z_MEM_ERROR: + fprintf(stderr, "zran: out of memory\n"); + break; + case Z_DATA_ERROR: + fprintf(stderr, "zran: compressed data error in %s\n", argv[1]); + break; + case Z_ERRNO: + fprintf(stderr, "zran: read error on %s\n", argv[1]); + break; + default: + fprintf(stderr, "zran: error %d while building index\n", len); + } + return 1; + } + fprintf(stderr, "zran: built index with %d access points\n", len); + + /* use index by reading some bytes from an arbitrary offset */ + offset = (index->list[index->have - 1].out << 1) / 3; + len = extract(in, index, offset, buf, CHUNK); + if (len < 0) + fprintf(stderr, "zran: extraction failed: %s error\n", + len == Z_MEM_ERROR ? "out of memory" : "input corrupted"); + else { + fwrite(buf, 1, len, stdout); + fprintf(stderr, "zran: extracted %d bytes at %llu\n", len, offset); + } + + /* clean up and exit */ + free_index(index); + fclose(in); + return 0; +} diff --git a/test/zlib/zlib-1.2.8/gzclose.c b/test/zlib/zlib-1.2.8/gzclose.c new file mode 100644 index 000000000..caeb99a31 --- /dev/null +++ b/test/zlib/zlib-1.2.8/gzclose.c @@ -0,0 +1,25 @@ +/* gzclose.c -- zlib gzclose() function + * Copyright (C) 2004, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* gzclose() is in a separate file so that it is linked in only if it is used. + That way the other gzclose functions can be used instead to avoid linking in + unneeded compression or decompression routines. */ +int ZEXPORT gzclose(file) + gzFile file; +{ +#ifndef NO_GZCOMPRESS + gz_statep state; + + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + return state->mode == GZ_READ ? gzclose_r(file) : gzclose_w(file); +#else + return gzclose_r(file); +#endif +} diff --git a/test/zlib/zlib-1.2.8/gzguts.h b/test/zlib/zlib-1.2.8/gzguts.h new file mode 100644 index 000000000..d87659d03 --- /dev/null +++ b/test/zlib/zlib-1.2.8/gzguts.h @@ -0,0 +1,209 @@ +/* gzguts.h -- zlib internal header definitions for gz* operations + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef _LARGEFILE64_SOURCE +# ifndef _LARGEFILE_SOURCE +# define _LARGEFILE_SOURCE 1 +# endif +# ifdef _FILE_OFFSET_BITS +# undef _FILE_OFFSET_BITS +# endif +#endif + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include +#include "zlib.h" +#ifdef STDC +# include +# include +# include +#endif +#include + +#ifdef _WIN32 +# include +#endif + +#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) +# include +#endif + +#ifdef WINAPI_FAMILY +# define open _open +# define read _read +# define write _write +# define close _close +#endif + +#ifdef NO_DEFLATE /* for compatibility with old definition */ +# define NO_GZCOMPRESS +#endif + +#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(__CYGWIN__) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) +# ifndef HAVE_VSNPRINTF +# define HAVE_VSNPRINTF +# endif +#endif + +#ifndef HAVE_VSNPRINTF +# ifdef MSDOS +/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), + but for now we just assume it doesn't. */ +# define NO_vsnprintf +# endif +# ifdef __TURBOC__ +# define NO_vsnprintf +# endif +# ifdef WIN32 +/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ +# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) +# define vsnprintf _vsnprintf +# endif +# endif +# endif +# ifdef __SASC +# define NO_vsnprintf +# endif +# ifdef VMS +# define NO_vsnprintf +# endif +# ifdef __OS400__ +# define NO_vsnprintf +# endif +# ifdef __MVS__ +# define NO_vsnprintf +# endif +#endif + +/* unlike snprintf (which is required in C99, yet still not supported by + Microsoft more than a decade later!), _snprintf does not guarantee null + termination of the result -- however this is only used in gzlib.c where + the result is assured to fit in the space provided */ +#ifdef _MSC_VER +# define snprintf _snprintf +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +/* gz* functions always use library allocation functions */ +#ifndef STDC + extern voidp malloc OF((uInt size)); + extern void free OF((voidpf ptr)); +#endif + +/* get errno and strerror definition */ +#if defined UNDER_CE +# include +# define zstrerror() gz_strwinerror((DWORD)GetLastError()) +#else +# ifndef NO_STRERROR +# include +# define zstrerror() strerror(errno) +# else +# define zstrerror() "stdio error (consult errno)" +# endif +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); +#endif + +/* default memLevel */ +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif + +/* default i/o buffer size -- double this for output when reading (this and + twice this must be able to fit in an unsigned type) */ +#define GZBUFSIZE 8192 + +/* gzip modes, also provide a little integrity check on the passed structure */ +#define GZ_NONE 0 +#define GZ_READ 7247 +#define GZ_WRITE 31153 +#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ + +/* values for gz_state how */ +#define LOOK 0 /* look for a gzip header */ +#define COPY 1 /* copy input directly */ +#define GZIP 2 /* decompress a gzip stream */ + +/* internal gzip file state data structure */ +typedef struct { + /* exposed contents for gzgetc() macro */ + struct gzFile_s x; /* "x" for exposed */ + /* x.have: number of bytes available at x.next */ + /* x.next: next output data to deliver or write */ + /* x.pos: current position in uncompressed data */ + /* used for both reading and writing */ + int mode; /* see gzip modes above */ + int fd; /* file descriptor */ + char *path; /* path or fd for error messages */ + unsigned size; /* buffer size, zero if not allocated yet */ + unsigned want; /* requested buffer size, default is GZBUFSIZE */ + unsigned char *in; /* input buffer */ + unsigned char *out; /* output buffer (double-sized when reading) */ + int direct; /* 0 if processing gzip, 1 if transparent */ + /* just for reading */ + int how; /* 0: get header, 1: copy, 2: decompress */ + z_off64_t start; /* where the gzip data started, for rewinding */ + int eof; /* true if end of input file reached */ + int past; /* true if read requested past end */ + /* just for writing */ + int level; /* compression level */ + int strategy; /* compression strategy */ + /* seek request */ + z_off64_t skip; /* amount to skip (already rewound if backwards) */ + int seek; /* true if seek request pending */ + /* error information */ + int err; /* error code */ + char *msg; /* error message */ + /* zlib inflate or deflate stream */ + z_stream strm; /* stream structure in-place (not a pointer) */ +} gz_state; +typedef gz_state FAR *gz_statep; + +/* shared functions */ +void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); +#if defined UNDER_CE +char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); +#endif + +/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t + value -- needed when comparing unsigned to z_off64_t, which is signed + (possible z_off64_t types off_t, off64_t, and long are all signed) */ +#ifdef INT_MAX +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) +#else +unsigned ZLIB_INTERNAL gz_intmax OF((void)); +# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) +#endif diff --git a/test/zlib/zlib-1.2.8/gzlib.c b/test/zlib/zlib-1.2.8/gzlib.c new file mode 100644 index 000000000..fae202ef8 --- /dev/null +++ b/test/zlib/zlib-1.2.8/gzlib.c @@ -0,0 +1,634 @@ +/* gzlib.c -- zlib functions common to reading and writing gzip files + * Copyright (C) 2004, 2010, 2011, 2012, 2013 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +#if defined(_WIN32) && !defined(__BORLANDC__) +# define LSEEK _lseeki64 +#else +#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0 +# define LSEEK lseek64 +#else +# define LSEEK lseek +#endif +#endif + +/* Local functions */ +local void gz_reset OF((gz_statep)); +local gzFile gz_open OF((const void *, int, const char *)); + +#if defined UNDER_CE + +/* Map the Windows error number in ERROR to a locale-dependent error message + string and return a pointer to it. Typically, the values for ERROR come + from GetLastError. + + The string pointed to shall not be modified by the application, but may be + overwritten by a subsequent call to gz_strwinerror + + The gz_strwinerror function does not change the current setting of + GetLastError. */ +char ZLIB_INTERNAL *gz_strwinerror (error) + DWORD error; +{ + static char buf[1024]; + + wchar_t *msgbuf; + DWORD lasterr = GetLastError(); + DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPVOID)&msgbuf, + 0, + NULL); + if (chars != 0) { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > sizeof (buf) - 1) { + chars = sizeof (buf) - 1; + msgbuf[chars] = 0; + } + + wcstombs(buf, msgbuf, chars + 1); + LocalFree(msgbuf); + } + else { + sprintf(buf, "unknown win32 error (%ld)", error); + } + + SetLastError(lasterr); + return buf; +} + +#endif /* UNDER_CE */ + +/* Reset gzip file state */ +local void gz_reset(state) + gz_statep state; +{ + state->x.have = 0; /* no output data available */ + if (state->mode == GZ_READ) { /* for reading ... */ + state->eof = 0; /* not at end of file */ + state->past = 0; /* have not read past end yet */ + state->how = LOOK; /* look for gzip header */ + } + state->seek = 0; /* no seek request pending */ + gz_error(state, Z_OK, NULL); /* clear error */ + state->x.pos = 0; /* no uncompressed data yet */ + state->strm.avail_in = 0; /* no input data yet */ +} + +/* Open a gzip file either by name or file descriptor. */ +local gzFile gz_open(path, fd, mode) + const void *path; + int fd; + const char *mode; +{ + gz_statep state; + size_t len; + int oflag; +#ifdef O_CLOEXEC + int cloexec = 0; +#endif +#ifdef O_EXCL + int exclusive = 0; +#endif + + /* check input */ + if (path == NULL) + return NULL; + + /* allocate gzFile structure to return */ + state = (gz_statep)malloc(sizeof(gz_state)); + if (state == NULL) + return NULL; + state->size = 0; /* no buffers allocated yet */ + state->want = GZBUFSIZE; /* requested buffer size */ + state->msg = NULL; /* no error message yet */ + + /* interpret mode */ + state->mode = GZ_NONE; + state->level = Z_DEFAULT_COMPRESSION; + state->strategy = Z_DEFAULT_STRATEGY; + state->direct = 0; + while (*mode) { + if (*mode >= '0' && *mode <= '9') + state->level = *mode - '0'; + else + switch (*mode) { + case 'r': + state->mode = GZ_READ; + break; +#ifndef NO_GZCOMPRESS + case 'w': + state->mode = GZ_WRITE; + break; + case 'a': + state->mode = GZ_APPEND; + break; +#endif + case '+': /* can't read and write at the same time */ + free(state); + return NULL; + case 'b': /* ignore -- will request binary anyway */ + break; +#ifdef O_CLOEXEC + case 'e': + cloexec = 1; + break; +#endif +#ifdef O_EXCL + case 'x': + exclusive = 1; + break; +#endif + case 'f': + state->strategy = Z_FILTERED; + break; + case 'h': + state->strategy = Z_HUFFMAN_ONLY; + break; + case 'R': + state->strategy = Z_RLE; + break; + case 'F': + state->strategy = Z_FIXED; + break; + case 'T': + state->direct = 1; + break; + default: /* could consider as an error, but just ignore */ + ; + } + mode++; + } + + /* must provide an "r", "w", or "a" */ + if (state->mode == GZ_NONE) { + free(state); + return NULL; + } + + /* can't force transparent read */ + if (state->mode == GZ_READ) { + if (state->direct) { + free(state); + return NULL; + } + state->direct = 1; /* for empty file */ + } + + /* save the path name for error messages */ +#ifdef _WIN32 + if (fd == -2) { + len = wcstombs(NULL, path, 0); + if (len == (size_t)-1) + len = 0; + } + else +#endif + len = strlen((const char *)path); + state->path = (char *)malloc(len + 1); + if (state->path == NULL) { + free(state); + return NULL; + } +#ifdef _WIN32 + if (fd == -2) + if (len) + wcstombs(state->path, path, len + 1); + else + *(state->path) = 0; + else +#endif +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(state->path, len + 1, "%s", (const char *)path); +#else + strcpy(state->path, path); +#endif + + /* compute the flags for open() */ + oflag = +#ifdef O_LARGEFILE + O_LARGEFILE | +#endif +#ifdef O_BINARY + O_BINARY | +#endif +#ifdef O_CLOEXEC + (cloexec ? O_CLOEXEC : 0) | +#endif + (state->mode == GZ_READ ? + O_RDONLY : + (O_WRONLY | O_CREAT | +#ifdef O_EXCL + (exclusive ? O_EXCL : 0) | +#endif + (state->mode == GZ_WRITE ? + O_TRUNC : + O_APPEND))); + + /* open the file with the appropriate flags (or just use fd) */ + state->fd = fd > -1 ? fd : ( +#ifdef _WIN32 + fd == -2 ? _wopen(path, oflag, 0666) : +#endif + open((const char *)path, oflag, 0666)); + if (state->fd == -1) { + free(state->path); + free(state); + return NULL; + } + if (state->mode == GZ_APPEND) + state->mode = GZ_WRITE; /* simplify later checks */ + + /* save the current position for rewinding (only if reading) */ + if (state->mode == GZ_READ) { + state->start = LSEEK(state->fd, 0, SEEK_CUR); + if (state->start == -1) state->start = 0; + } + + /* initialize stream */ + gz_reset(state); + + /* return stream */ + return (gzFile)state; +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen(path, mode) + const char *path; + const char *mode; +{ + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzopen64(path, mode) + const char *path; + const char *mode; +{ + return gz_open(path, -1, mode); +} + +/* -- see zlib.h -- */ +gzFile ZEXPORT gzdopen(fd, mode) + int fd; + const char *mode; +{ + char *path; /* identifier for error messages */ + gzFile gz; + + if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) + return NULL; +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(path, 7 + 3 * sizeof(int), "", fd); /* for debugging */ +#else + sprintf(path, "", fd); /* for debugging */ +#endif + gz = gz_open(path, fd, mode); + free(path); + return gz; +} + +/* -- see zlib.h -- */ +#ifdef _WIN32 +gzFile ZEXPORT gzopen_w(path, mode) + const wchar_t *path; + const char *mode; +{ + return gz_open(path, -2, mode); +} +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzbuffer(file, size) + gzFile file; + unsigned size; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* make sure we haven't already allocated memory */ + if (state->size != 0) + return -1; + + /* check and set requested size */ + if (size < 2) + size = 2; /* need two bytes to check magic header */ + state->want = size; + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzrewind(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* back up and start over */ + if (LSEEK(state->fd, state->start, SEEK_SET) == -1) + return -1; + gz_reset(state); + return 0; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzseek64(file, offset, whence) + gzFile file; + z_off64_t offset; + int whence; +{ + unsigned n; + z_off64_t ret; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* check that there's no error */ + if (state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + + /* can only seek from start or relative to current position */ + if (whence != SEEK_SET && whence != SEEK_CUR) + return -1; + + /* normalize offset to a SEEK_CUR specification */ + if (whence == SEEK_SET) + offset -= state->x.pos; + else if (state->seek) + offset += state->skip; + state->seek = 0; + + /* if within raw area while reading, just go there */ + if (state->mode == GZ_READ && state->how == COPY && + state->x.pos + offset >= 0) { + ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR); + if (ret == -1) + return -1; + state->x.have = 0; + state->eof = 0; + state->past = 0; + state->seek = 0; + gz_error(state, Z_OK, NULL); + state->strm.avail_in = 0; + state->x.pos += offset; + return state->x.pos; + } + + /* calculate skip amount, rewinding if needed for back seek when reading */ + if (offset < 0) { + if (state->mode != GZ_READ) /* writing -- can't go backwards */ + return -1; + offset += state->x.pos; + if (offset < 0) /* before start of file! */ + return -1; + if (gzrewind(file) == -1) /* rewind, then skip to offset */ + return -1; + } + + /* if reading, skip what's in output buffer (one less gzgetc() check) */ + if (state->mode == GZ_READ) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > offset ? + (unsigned)offset : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + offset -= n; + } + + /* request skip (if not zero) */ + if (offset) { + state->seek = 1; + state->skip = offset; + } + return state->x.pos + offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzseek(file, offset, whence) + gzFile file; + z_off_t offset; + int whence; +{ + z_off64_t ret; + + ret = gzseek64(file, (z_off64_t)offset, whence); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gztell64(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* return position */ + return state->x.pos + (state->seek ? state->skip : 0); +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gztell(file) + gzFile file; +{ + z_off64_t ret; + + ret = gztell64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +z_off64_t ZEXPORT gzoffset64(file) + gzFile file; +{ + z_off64_t offset; + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return -1; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return -1; + + /* compute and return effective offset in file */ + offset = LSEEK(state->fd, 0, SEEK_CUR); + if (offset == -1) + return -1; + if (state->mode == GZ_READ) /* reading */ + offset -= state->strm.avail_in; /* don't count buffered input */ + return offset; +} + +/* -- see zlib.h -- */ +z_off_t ZEXPORT gzoffset(file) + gzFile file; +{ + z_off64_t ret; + + ret = gzoffset64(file); + return ret == (z_off_t)ret ? (z_off_t)ret : -1; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzeof(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return 0; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return 0; + + /* return end-of-file state */ + return state->mode == GZ_READ ? state->past : 0; +} + +/* -- see zlib.h -- */ +const char * ZEXPORT gzerror(file, errnum) + gzFile file; + int *errnum; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return NULL; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return NULL; + + /* return error information */ + if (errnum != NULL) + *errnum = state->err; + return state->err == Z_MEM_ERROR ? "out of memory" : + (state->msg == NULL ? "" : state->msg); +} + +/* -- see zlib.h -- */ +void ZEXPORT gzclearerr(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure and check integrity */ + if (file == NULL) + return; + state = (gz_statep)file; + if (state->mode != GZ_READ && state->mode != GZ_WRITE) + return; + + /* clear error and end-of-file */ + if (state->mode == GZ_READ) { + state->eof = 0; + state->past = 0; + } + gz_error(state, Z_OK, NULL); +} + +/* Create an error message in allocated memory and set state->err and + state->msg accordingly. Free any previous error message already there. Do + not try to free or allocate space if the error is Z_MEM_ERROR (out of + memory). Simply save the error message as a static string. If there is an + allocation failure constructing the error message, then convert the error to + out of memory. */ +void ZLIB_INTERNAL gz_error(state, err, msg) + gz_statep state; + int err; + const char *msg; +{ + /* free previously allocated message and clear */ + if (state->msg != NULL) { + if (state->err != Z_MEM_ERROR) + free(state->msg); + state->msg = NULL; + } + + /* if fatal, set state->x.have to 0 so that the gzgetc() macro fails */ + if (err != Z_OK && err != Z_BUF_ERROR) + state->x.have = 0; + + /* set error code, and if no message, then done */ + state->err = err; + if (msg == NULL) + return; + + /* for an out of memory error, return literal string when requested */ + if (err == Z_MEM_ERROR) + return; + + /* construct error message with path */ + if ((state->msg = (char *)malloc(strlen(state->path) + strlen(msg) + 3)) == + NULL) { + state->err = Z_MEM_ERROR; + return; + } +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, + "%s%s%s", state->path, ": ", msg); +#else + strcpy(state->msg, state->path); + strcat(state->msg, ": "); + strcat(state->msg, msg); +#endif + return; +} + +#ifndef INT_MAX +/* portably return maximum value for an int (when limits.h presumed not + available) -- we need to do this to cover cases where 2's complement not + used, since C standard permits 1's complement and sign-bit representations, + otherwise we could just use ((unsigned)-1) >> 1 */ +unsigned ZLIB_INTERNAL gz_intmax() +{ + unsigned p, q; + + p = 1; + do { + q = p; + p <<= 1; + p++; + } while (p > q); + return q >> 1; +} +#endif diff --git a/test/zlib/zlib-1.2.8/gzread.c b/test/zlib/zlib-1.2.8/gzread.c new file mode 100644 index 000000000..bf4538eb2 --- /dev/null +++ b/test/zlib/zlib-1.2.8/gzread.c @@ -0,0 +1,594 @@ +/* gzread.c -- zlib functions for reading gzip files + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Local functions */ +local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); +local int gz_avail OF((gz_statep)); +local int gz_look OF((gz_statep)); +local int gz_decomp OF((gz_statep)); +local int gz_fetch OF((gz_statep)); +local int gz_skip OF((gz_statep, z_off64_t)); + +/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from + state->fd, and update state->eof, state->err, and state->msg as appropriate. + This function needs to loop on read(), since read() is not guaranteed to + read the number of bytes requested, depending on the type of descriptor. */ +local int gz_load(state, buf, len, have) + gz_statep state; + unsigned char *buf; + unsigned len; + unsigned *have; +{ + int ret; + + *have = 0; + do { + ret = read(state->fd, buf + *have, len - *have); + if (ret <= 0) + break; + *have += ret; + } while (*have < len); + if (ret < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (ret == 0) + state->eof = 1; + return 0; +} + +/* Load up input buffer and set eof flag if last data loaded -- return -1 on + error, 0 otherwise. Note that the eof flag is set when the end of the input + file is reached, even though there may be unused data in the buffer. Once + that data has been used, no more attempts will be made to read the file. + If strm->avail_in != 0, then the current data is moved to the beginning of + the input buffer, and then the remainder of the buffer is loaded with the + available data from the input file. */ +local int gz_avail(state) + gz_statep state; +{ + unsigned got; + z_streamp strm = &(state->strm); + + if (state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + if (state->eof == 0) { + if (strm->avail_in) { /* copy what's there to the start */ + unsigned char *p = state->in; + unsigned const char *q = strm->next_in; + unsigned n = strm->avail_in; + do { + *p++ = *q++; + } while (--n); + } + if (gz_load(state, state->in + strm->avail_in, + state->size - strm->avail_in, &got) == -1) + return -1; + strm->avail_in += got; + strm->next_in = state->in; + } + return 0; +} + +/* Look for gzip header, set up for inflate or copy. state->x.have must be 0. + If this is the first time in, allocate required memory. state->how will be + left unchanged if there is no more input data available, will be set to COPY + if there is no gzip header and direct copying will be performed, or it will + be set to GZIP for decompression. If direct copying, then leftover input + data from the input buffer will be copied to the output buffer. In that + case, all further file reads will be directly to either the output buffer or + a user buffer. If decompressing, the inflate state will be initialized. + gz_look() will return 0 on success or -1 on failure. */ +local int gz_look(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + /* allocate read buffers and inflate memory */ + if (state->size == 0) { + /* allocate buffers */ + state->in = (unsigned char *)malloc(state->want); + state->out = (unsigned char *)malloc(state->want << 1); + if (state->in == NULL || state->out == NULL) { + if (state->out != NULL) + free(state->out); + if (state->in != NULL) + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + state->size = state->want; + + /* allocate inflate memory */ + state->strm.zalloc = Z_NULL; + state->strm.zfree = Z_NULL; + state->strm.opaque = Z_NULL; + state->strm.avail_in = 0; + state->strm.next_in = Z_NULL; + if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) { /* gunzip */ + free(state->out); + free(state->in); + state->size = 0; + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + } + + /* get at least the magic bytes in the input buffer */ + if (strm->avail_in < 2) { + if (gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) + return 0; + } + + /* look for gzip magic bytes -- if there, do gzip decoding (note: there is + a logical dilemma here when considering the case of a partially written + gzip file, to wit, if a single 31 byte is written, then we cannot tell + whether this is a single-byte file, or just a partially written gzip + file -- for here we assume that if a gzip file is being written, then + the header will be written in a single operation, so that reading a + single byte is sufficient indication that it is not a gzip file) */ + if (strm->avail_in > 1 && + strm->next_in[0] == 31 && strm->next_in[1] == 139) { + inflateReset(strm); + state->how = GZIP; + state->direct = 0; + return 0; + } + + /* no gzip header -- if we were decoding gzip before, then this is trailing + garbage. Ignore the trailing garbage and finish. */ + if (state->direct == 0) { + strm->avail_in = 0; + state->eof = 1; + state->x.have = 0; + return 0; + } + + /* doing raw i/o, copy any leftover input to output -- this assumes that + the output buffer is larger than the input buffer, which also assures + space for gzungetc() */ + state->x.next = state->out; + if (strm->avail_in) { + memcpy(state->x.next, strm->next_in, strm->avail_in); + state->x.have = strm->avail_in; + strm->avail_in = 0; + } + state->how = COPY; + state->direct = 1; + return 0; +} + +/* Decompress from input to the provided next_out and avail_out in the state. + On return, state->x.have and state->x.next point to the just decompressed + data. If the gzip stream completes, state->how is reset to LOOK to look for + the next gzip stream or raw data, once state->x.have is depleted. Returns 0 + on success, -1 on failure. */ +local int gz_decomp(state) + gz_statep state; +{ + int ret = Z_OK; + unsigned had; + z_streamp strm = &(state->strm); + + /* fill output buffer up to end of deflate stream */ + had = strm->avail_out; + do { + /* get more input for inflate() */ + if (strm->avail_in == 0 && gz_avail(state) == -1) + return -1; + if (strm->avail_in == 0) { + gz_error(state, Z_BUF_ERROR, "unexpected end of file"); + break; + } + + /* decompress and handle errors */ + ret = inflate(strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { + gz_error(state, Z_STREAM_ERROR, + "internal error: inflate stream corrupt"); + return -1; + } + if (ret == Z_MEM_ERROR) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ + gz_error(state, Z_DATA_ERROR, + strm->msg == NULL ? "compressed data error" : strm->msg); + return -1; + } + } while (strm->avail_out && ret != Z_STREAM_END); + + /* update available output */ + state->x.have = had - strm->avail_out; + state->x.next = strm->next_out - state->x.have; + + /* if the gzip stream completed successfully, look for another */ + if (ret == Z_STREAM_END) + state->how = LOOK; + + /* good decompression */ + return 0; +} + +/* Fetch data and put it in the output buffer. Assumes state->x.have is 0. + Data is either copied from the input file or decompressed from the input + file depending on state->how. If state->how is LOOK, then a gzip header is + looked for to determine whether to copy or decompress. Returns -1 on error, + otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the + end of the input file has been reached and all data has been processed. */ +local int gz_fetch(state) + gz_statep state; +{ + z_streamp strm = &(state->strm); + + do { + switch(state->how) { + case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */ + if (gz_look(state) == -1) + return -1; + if (state->how == LOOK) + return 0; + break; + case COPY: /* -> COPY */ + if (gz_load(state, state->out, state->size << 1, &(state->x.have)) + == -1) + return -1; + state->x.next = state->out; + return 0; + case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */ + strm->avail_out = state->size << 1; + strm->next_out = state->out; + if (gz_decomp(state) == -1) + return -1; + } + } while (state->x.have == 0 && (!state->eof || strm->avail_in)); + return 0; +} + +/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */ +local int gz_skip(state, len) + gz_statep state; + z_off64_t len; +{ + unsigned n; + + /* skip over len bytes or reach end-of-file, whichever comes first */ + while (len) + /* skip over whatever is in output buffer */ + if (state->x.have) { + n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ? + (unsigned)len : state->x.have; + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + len -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && state->strm.avail_in == 0) + break; + + /* need more data to skip -- load up output buffer */ + else { + /* get more output, looking for header if required */ + if (gz_fetch(state) == -1) + return -1; + } + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzread(file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + unsigned got, n; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids the flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); + return -1; + } + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return -1; + } + + /* get len bytes to buf, or less than len if at the end */ + got = 0; + do { + /* first just try copying data from the output buffer */ + if (state->x.have) { + n = state->x.have > len ? len : state->x.have; + memcpy(buf, state->x.next, n); + state->x.next += n; + state->x.have -= n; + } + + /* output buffer empty -- return if we're at the end of the input */ + else if (state->eof && strm->avail_in == 0) { + state->past = 1; /* tried to read past end */ + break; + } + + /* need output data -- for small len or new stream load up our output + buffer */ + else if (state->how == LOOK || len < (state->size << 1)) { + /* get more output, looking for header if required */ + if (gz_fetch(state) == -1) + return -1; + continue; /* no progress yet -- go back to copy above */ + /* the copy above assures that we will leave with space in the + output buffer, allowing at least one gzungetc() to succeed */ + } + + /* large len -- read directly into user buffer */ + else if (state->how == COPY) { /* read directly */ + if (gz_load(state, (unsigned char *)buf, len, &n) == -1) + return -1; + } + + /* large len -- decompress directly into user buffer */ + else { /* state->how == GZIP */ + strm->avail_out = len; + strm->next_out = (unsigned char *)buf; + if (gz_decomp(state) == -1) + return -1; + n = state->x.have; + state->x.have = 0; + } + + /* update progress */ + len -= n; + buf = (char *)buf + n; + got += n; + state->x.pos += n; + } while (len); + + /* return number of bytes read into user buffer (will fit in int) */ + return (int)got; +} + +/* -- see zlib.h -- */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +#else +# undef gzgetc +#endif +int ZEXPORT gzgetc(file) + gzFile file; +{ + int ret; + unsigned char buf[1]; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* try output buffer (no need to check for skip request) */ + if (state->x.have) { + state->x.have--; + state->x.pos++; + return *(state->x.next)++; + } + + /* nothing there -- try gzread() */ + ret = gzread(file, buf, 1); + return ret < 1 ? -1 : buf[0]; +} + +int ZEXPORT gzgetc_(file) +gzFile file; +{ + return gzgetc(file); +} + +/* -- see zlib.h -- */ +int ZEXPORT gzungetc(c, file) + int c; + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return -1; + } + + /* can't push EOF */ + if (c < 0) + return -1; + + /* if output buffer empty, put byte at end (allows more pushing) */ + if (state->x.have == 0) { + state->x.have = 1; + state->x.next = state->out + (state->size << 1) - 1; + state->x.next[0] = c; + state->x.pos--; + state->past = 0; + return c; + } + + /* if no room, give up (must have already done a gzungetc()) */ + if (state->x.have == (state->size << 1)) { + gz_error(state, Z_DATA_ERROR, "out of room to push characters"); + return -1; + } + + /* slide output data if needed and insert byte before existing data */ + if (state->x.next == state->out) { + unsigned char *src = state->out + state->x.have; + unsigned char *dest = state->out + (state->size << 1); + while (src > state->out) + *--dest = *--src; + state->x.next = dest; + } + state->x.have++; + state->x.next--; + state->x.next[0] = c; + state->x.pos--; + state->past = 0; + return c; +} + +/* -- see zlib.h -- */ +char * ZEXPORT gzgets(file, buf, len) + gzFile file; + char *buf; + int len; +{ + unsigned left, n; + char *str; + unsigned char *eol; + gz_statep state; + + /* check parameters and get internal structure */ + if (file == NULL || buf == NULL || len < 1) + return NULL; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return NULL; + + /* process a skip request */ + if (state->seek) { + state->seek = 0; + if (gz_skip(state, state->skip) == -1) + return NULL; + } + + /* copy output bytes up to new line or len - 1, whichever comes first -- + append a terminating zero to the string (we don't check for a zero in + the contents, let the user worry about that) */ + str = buf; + left = (unsigned)len - 1; + if (left) do { + /* assure that something is in the output buffer */ + if (state->x.have == 0 && gz_fetch(state) == -1) + return NULL; /* error */ + if (state->x.have == 0) { /* end of file */ + state->past = 1; /* read past end */ + break; /* return what we have */ + } + + /* look for end-of-line in current output buffer */ + n = state->x.have > left ? left : state->x.have; + eol = (unsigned char *)memchr(state->x.next, '\n', n); + if (eol != NULL) + n = (unsigned)(eol - state->x.next) + 1; + + /* copy through end-of-line, or remainder if not found */ + memcpy(buf, state->x.next, n); + state->x.have -= n; + state->x.next += n; + state->x.pos += n; + left -= n; + buf += n; + } while (left && eol == NULL); + + /* return terminated string, or if nothing, end of file */ + if (buf == str) + return NULL; + buf[0] = 0; + return str; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzdirect(file) + gzFile file; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* if the state is not known, but we can find out, then do so (this is + mainly for right after a gzopen() or gzdopen()) */ + if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0) + (void)gz_look(state); + + /* return 1 if transparent, 0 if processing a gzip stream */ + return state->direct; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_r(file) + gzFile file; +{ + int ret, err; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're reading */ + if (state->mode != GZ_READ) + return Z_STREAM_ERROR; + + /* free memory and close file */ + if (state->size) { + inflateEnd(&(state->strm)); + free(state->out); + free(state->in); + } + err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK; + gz_error(state, Z_OK, NULL); + free(state->path); + ret = close(state->fd); + free(state); + return ret ? Z_ERRNO : err; +} diff --git a/test/zlib/zlib-1.2.8/gzwrite.c b/test/zlib/zlib-1.2.8/gzwrite.c new file mode 100644 index 000000000..aa767fbf6 --- /dev/null +++ b/test/zlib/zlib-1.2.8/gzwrite.c @@ -0,0 +1,577 @@ +/* gzwrite.c -- zlib functions for writing gzip files + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "gzguts.h" + +/* Local functions */ +local int gz_init OF((gz_statep)); +local int gz_comp OF((gz_statep, int)); +local int gz_zero OF((gz_statep, z_off64_t)); + +/* Initialize state for writing a gzip file. Mark initialization by setting + state->size to non-zero. Return -1 on failure or 0 on success. */ +local int gz_init(state) + gz_statep state; +{ + int ret; + z_streamp strm = &(state->strm); + + /* allocate input buffer */ + state->in = (unsigned char *)malloc(state->want); + if (state->in == NULL) { + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* only need output buffer and deflate state if compressing */ + if (!state->direct) { + /* allocate output buffer */ + state->out = (unsigned char *)malloc(state->want); + if (state->out == NULL) { + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + + /* allocate deflate memory, set up for gzip compression */ + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; + strm->opaque = Z_NULL; + ret = deflateInit2(strm, state->level, Z_DEFLATED, + MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy); + if (ret != Z_OK) { + free(state->out); + free(state->in); + gz_error(state, Z_MEM_ERROR, "out of memory"); + return -1; + } + } + + /* mark state as initialized */ + state->size = state->want; + + /* initialize write buffer if compressing */ + if (!state->direct) { + strm->avail_out = state->size; + strm->next_out = state->out; + state->x.next = strm->next_out; + } + return 0; +} + +/* Compress whatever is at avail_in and next_in and write to the output file. + Return -1 if there is an error writing to the output file, otherwise 0. + flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, + then the deflate() state is reset to start a new gzip stream. If gz->direct + is true, then simply write to the output file without compressing, and + ignore flush. */ +local int gz_comp(state, flush) + gz_statep state; + int flush; +{ + int ret, got; + unsigned have; + z_streamp strm = &(state->strm); + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return -1; + + /* write directly if requested */ + if (state->direct) { + got = write(state->fd, strm->next_in, strm->avail_in); + if (got < 0 || (unsigned)got != strm->avail_in) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + strm->avail_in = 0; + return 0; + } + + /* run deflate() on provided input until it produces no more output */ + ret = Z_OK; + do { + /* write out current buffer contents if full, or if flushing, but if + doing Z_FINISH then don't write until we get to Z_STREAM_END */ + if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && + (flush != Z_FINISH || ret == Z_STREAM_END))) { + have = (unsigned)(strm->next_out - state->x.next); + if (have && ((got = write(state->fd, state->x.next, have)) < 0 || + (unsigned)got != have)) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + if (strm->avail_out == 0) { + strm->avail_out = state->size; + strm->next_out = state->out; + } + state->x.next = strm->next_out; + } + + /* compress */ + have = strm->avail_out; + ret = deflate(strm, flush); + if (ret == Z_STREAM_ERROR) { + gz_error(state, Z_STREAM_ERROR, + "internal error: deflate stream corrupt"); + return -1; + } + have -= strm->avail_out; + } while (have); + + /* if that completed a deflate stream, allow another to start */ + if (flush == Z_FINISH) + deflateReset(strm); + + /* all done, no errors */ + return 0; +} + +/* Compress len zeros to output. Return -1 on error, 0 on success. */ +local int gz_zero(state, len) + gz_statep state; + z_off64_t len; +{ + int first; + unsigned n; + z_streamp strm = &(state->strm); + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + + /* compress len zeros (len guaranteed > 0) */ + first = 1; + while (len) { + n = GT_OFF(state->size) || (z_off64_t)state->size > len ? + (unsigned)len : state->size; + if (first) { + memset(state->in, 0, n); + first = 0; + } + strm->avail_in = n; + strm->next_in = state->in; + state->x.pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return -1; + len -= n; + } + return 0; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzwrite(file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + unsigned put = len; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids the flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); + return 0; + } + + /* if len is zero, avoid unnecessary operations */ + if (len == 0) + return 0; + + /* allocate memory if this is the first time through */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* for small len, copy to input buffer, otherwise compress directly */ + if (len < state->size) { + /* copy to input buffer, compress when full */ + do { + unsigned have, copy; + + if (strm->avail_in == 0) + strm->next_in = state->in; + have = (unsigned)((strm->next_in + strm->avail_in) - state->in); + copy = state->size - have; + if (copy > len) + copy = len; + memcpy(state->in + have, buf, copy); + strm->avail_in += copy; + state->x.pos += copy; + buf = (const char *)buf + copy; + len -= copy; + if (len && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + } while (len); + } + else { + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* directly compress user buffer to file */ + strm->avail_in = len; + strm->next_in = (z_const Bytef *)buf; + state->x.pos += len; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + } + + /* input was all buffered or compressed (put will fit in int) */ + return (int)put; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputc(file, c) + gzFile file; + int c; +{ + unsigned have; + unsigned char buf[1]; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* try writing to input buffer for speed (state->size == 0 if buffer not + initialized) */ + if (state->size) { + if (strm->avail_in == 0) + strm->next_in = state->in; + have = (unsigned)((strm->next_in + strm->avail_in) - state->in); + if (have < state->size) { + state->in[have] = c; + strm->avail_in++; + state->x.pos++; + return c & 0xff; + } + } + + /* no room in buffer or not initialized, use gz_write() */ + buf[0] = c; + if (gzwrite(file, buf, 1) != 1) + return -1; + return c & 0xff; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzputs(file, str) + gzFile file; + const char *str; +{ + int ret; + unsigned len; + + /* write string */ + len = (unsigned)strlen(str); + ret = gzwrite(file, str, len); + return ret == 0 && len != 0 ? -1 : ret; +} + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +#include + +/* -- see zlib.h -- */ +int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) +{ + int size, len; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* do the printf() into the input buffer, put length in len */ + size = (int)(state->size); + state->in[size - 1] = 0; +#ifdef NO_vsnprintf +# ifdef HAS_vsprintf_void + (void)vsprintf((char *)(state->in), format, va); + for (len = 0; len < size; len++) + if (state->in[len] == 0) break; +# else + len = vsprintf((char *)(state->in), format, va); +# endif +#else +# ifdef HAS_vsnprintf_void + (void)vsnprintf((char *)(state->in), size, format, va); + len = strlen((char *)(state->in)); +# else + len = vsnprintf((char *)(state->in), size, format, va); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) + return 0; + + /* update buffer and position, defer compression until needed */ + strm->avail_in = (unsigned)len; + strm->next_in = state->in; + state->x.pos += len; + return len; +} + +int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) +{ + va_list va; + int ret; + + va_start(va, format); + ret = gzvprintf(file, format, va); + va_end(va); + return ret; +} + +#else /* !STDC && !Z_HAVE_STDARG_H */ + +/* -- see zlib.h -- */ +int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20) + gzFile file; + const char *format; + int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, + a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; +{ + int size, len; + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that can really pass pointer in ints */ + if (sizeof(int) != sizeof(void *)) + return 0; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* make sure we have some buffer space */ + if (state->size == 0 && gz_init(state) == -1) + return 0; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return 0; + } + + /* consume whatever's left in the input buffer */ + if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + + /* do the printf() into the input buffer, put length in len */ + size = (int)(state->size); + state->in[size - 1] = 0; +#ifdef NO_snprintf +# ifdef HAS_sprintf_void + sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + for (len = 0; len < size; len++) + if (state->in[len] == 0) break; +# else + len = sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); +# endif +#else +# ifdef HAS_snprintf_void + snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen((char *)(state->in)); +# else + len = snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, + a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, + a19, a20); +# endif +#endif + + /* check that printf() results fit in buffer */ + if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) + return 0; + + /* update buffer and position, defer compression until needed */ + strm->avail_in = (unsigned)len; + strm->next_in = state->in; + state->x.pos += len; + return len; +} + +#endif + +/* -- see zlib.h -- */ +int ZEXPORT gzflush(file, flush) + gzFile file; + int flush; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* check flush parameter */ + if (flush < 0 || flush > Z_FINISH) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* compress remaining data with requested flush */ + gz_comp(state, flush); + return state->err; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzsetparams(file, level, strategy) + gzFile file; + int level; + int strategy; +{ + gz_statep state; + z_streamp strm; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + strm = &(state->strm); + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return Z_STREAM_ERROR; + + /* if no change is requested, then do nothing */ + if (level == state->level && strategy == state->strategy) + return Z_OK; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + return -1; + } + + /* change compression parameters for subsequent input */ + if (state->size) { + /* flush previous input with previous parameters before changing */ + if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1) + return state->err; + deflateParams(strm, level, strategy); + } + state->level = level; + state->strategy = strategy; + return Z_OK; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzclose_w(file) + gzFile file; +{ + int ret = Z_OK; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return Z_STREAM_ERROR; + state = (gz_statep)file; + + /* check that we're writing */ + if (state->mode != GZ_WRITE) + return Z_STREAM_ERROR; + + /* check for seek request */ + if (state->seek) { + state->seek = 0; + if (gz_zero(state, state->skip) == -1) + ret = state->err; + } + + /* flush, free memory, and close file */ + if (gz_comp(state, Z_FINISH) == -1) + ret = state->err; + if (state->size) { + if (!state->direct) { + (void)deflateEnd(&(state->strm)); + free(state->out); + } + free(state->in); + } + gz_error(state, Z_OK, NULL); + free(state->path); + if (close(state->fd) == -1) + ret = Z_ERRNO; + free(state); + return ret; +} diff --git a/test/zlib/zlib-1.2.8/infback.c b/test/zlib/zlib-1.2.8/infback.c new file mode 100644 index 000000000..f3833c2e4 --- /dev/null +++ b/test/zlib/zlib-1.2.8/infback.c @@ -0,0 +1,640 @@ +/* infback.c -- inflate using a call-back interface + * Copyright (C) 1995-2011 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + This code is largely copied from inflate.c. Normally either infback.o or + inflate.o would be linked into an application--not both. The interface + with inffast.c is retained so that optimized assembler-coded versions of + inflate_fast() can be used with either inflate.c or infback.c. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); + +/* + strm provides memory allocation functions in zalloc and zfree, or + Z_NULL to use the library memory allocation functions. + + windowBits is in the range 8..15, and window is a user-supplied + window and output buffer that is 2**windowBits bytes. + */ +int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size) +z_streamp strm; +int windowBits; +unsigned char FAR *window; +const char *version; +int stream_size; +{ + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL || window == Z_NULL || + windowBits < 8 || windowBits > 15) + return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *)ZALLOC(strm, 1, + sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->dmax = 32768U; + state->wbits = windowBits; + state->wsize = 1U << windowBits; + state->window = window; + state->wnext = 0; + state->whave = 0; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +/* Macros for inflateBack(): */ + +/* Load returned state from inflate_fast() */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Set state from registers for inflate_fast() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Assure that some input is available. If input is requested, but denied, + then return a Z_BUF_ERROR from inflateBack(). */ +#define PULL() \ + do { \ + if (have == 0) { \ + have = in(in_desc, &next); \ + if (have == 0) { \ + next = Z_NULL; \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflateBack() + with an error if there is no input available. */ +#define PULLBYTE() \ + do { \ + PULL(); \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflateBack() with + an error. */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* Assure that some output space is available, by writing out the window + if it's full. If the write fails, return from inflateBack() with a + Z_BUF_ERROR. */ +#define ROOM() \ + do { \ + if (left == 0) { \ + put = state->window; \ + left = state->wsize; \ + state->whave = left; \ + if (out(out_desc, put, left)) { \ + ret = Z_BUF_ERROR; \ + goto inf_leave; \ + } \ + } \ + } while (0) + +/* + strm provides the memory allocation functions and window buffer on input, + and provides information on the unused input on return. For Z_DATA_ERROR + returns, strm will also provide an error message. + + in() and out() are the call-back input and output functions. When + inflateBack() needs more input, it calls in(). When inflateBack() has + filled the window with output, or when it completes with data in the + window, it calls out() to write out the data. The application must not + change the provided input until in() is called again or inflateBack() + returns. The application must not change the window/output buffer until + inflateBack() returns. + + in() and out() are called with a descriptor parameter provided in the + inflateBack() call. This parameter can be a structure that provides the + information required to do the read or write, as well as accumulated + information on the input and output such as totals and check values. + + in() should return zero on failure. out() should return non-zero on + failure. If either in() or out() fails, than inflateBack() returns a + Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it + was in() or out() that caused in the error. Otherwise, inflateBack() + returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format + error, or Z_MEM_ERROR if it could not allocate memory for the state. + inflateBack() can also return Z_STREAM_ERROR if the input parameters + are not correct, i.e. strm is Z_NULL or the state was not initialized. + */ +int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc) +z_streamp strm; +in_func in; +void FAR *in_desc; +out_func out; +void FAR *out_desc; +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + /* Check that the strm exists and that the state was initialized */ + if (strm == Z_NULL || strm->state == Z_NULL) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* Reset the state */ + strm->msg = Z_NULL; + state->mode = TYPE; + state->last = 0; + state->whave = 0; + next = strm->next_in; + have = next != Z_NULL ? strm->avail_in : 0; + hold = 0; + bits = 0; + put = state->window; + left = state->wsize; + + /* Inflate until end of block marked as last */ + for (;;) + switch (state->mode) { + case TYPE: + /* determine and dispatch block type */ + if (state->last) { + BYTEBITS(); + state->mode = DONE; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN; /* decode codes */ + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + + case STORED: + /* get and verify stored block length */ + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + + /* copy stored block from input to output */ + while (state->length != 0) { + copy = state->length; + PULL(); + ROOM(); + if (copy > have) copy = have; + if (copy > left) copy = left; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + + case TABLE: + /* get dynamic table entries descriptor */ + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + + /* get code length code lengths (not a typo) */ + state->have = 0; + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + + /* get length and distance code code lengths */ + state->have = 0; + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = (unsigned)(state->lens[state->have - 1]); + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (code const FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (code const FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN; + + case LEN: + /* use inflate_fast() if we have enough input and output */ + if (have >= 6 && left >= 258) { + RESTORE(); + if (state->whave < state->wsize) + state->whave = state->wsize - left; + inflate_fast(strm, state->wsize); + LOAD(); + break; + } + + /* get a literal, length, or end-of-block code */ + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + state->length = (unsigned)here.val; + + /* process literal */ + if (here.op == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + ROOM(); + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + } + + /* process end of block */ + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + + /* invalid code */ + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + + /* length code -- get extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + + /* get distance code */ + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + } + DROPBITS(here.bits); + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + + /* get distance extra bits, if any */ + state->extra = (unsigned)(here.op) & 15; + if (state->extra != 0) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + } + if (state->offset > state->wsize - (state->whave < state->wsize ? + left : 0)) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + + /* copy match from window to output */ + do { + ROOM(); + copy = state->wsize - state->offset; + if (copy < left) { + from = put + copy; + copy = left - copy; + } + else { + from = put - state->offset; + copy = left; + } + if (copy > state->length) copy = state->length; + state->length -= copy; + left -= copy; + do { + *put++ = *from++; + } while (--copy); + } while (state->length != 0); + break; + + case DONE: + /* inflate stream terminated properly -- write leftover output */ + ret = Z_STREAM_END; + if (left < state->wsize) { + if (out(out_desc, state->window, state->wsize - left)) + ret = Z_BUF_ERROR; + } + goto inf_leave; + + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + + default: /* can't happen, but makes compilers happy */ + ret = Z_STREAM_ERROR; + goto inf_leave; + } + + /* Return unused input */ + inf_leave: + strm->next_in = next; + strm->avail_in = have; + return ret; +} + +int ZEXPORT inflateBackEnd(strm) +z_streamp strm; +{ + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} diff --git a/test/zlib/zlib-1.2.8/inffast.c b/test/zlib/zlib-1.2.8/inffast.c new file mode 100644 index 000000000..bda59ceb6 --- /dev/null +++ b/test/zlib/zlib-1.2.8/inffast.c @@ -0,0 +1,340 @@ +/* inffast.c -- fast decoding + * Copyright (C) 1995-2008, 2010, 2013 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifndef ASMINF + +/* Allow machine dependent optimization for post-increment or pre-increment. + Based on testing to date, + Pre-increment preferred for: + - PowerPC G3 (Adler) + - MIPS R5000 (Randers-Pehrson) + Post-increment preferred for: + - none + No measurable difference: + - Pentium III (Anderson) + - M68060 (Nikl) + */ +#ifdef POSTINC +# define OFF 0 +# define PUP(a) *(a)++ +#else +# define OFF 1 +# define PUP(a) *++(a) +#endif + +/* + Decode literal, length, and distance codes and write out the resulting + literal and match bytes until either not enough input or output is + available, an end-of-block is encountered, or a data error is encountered. + When large enough input and output buffers are supplied to inflate(), for + example, a 16K input buffer and a 64K output buffer, more than 95% of the + inflate execution time is spent in this routine. + + Entry assumptions: + + state->mode == LEN + strm->avail_in >= 6 + strm->avail_out >= 258 + start >= strm->avail_out + state->bits < 8 + + On return, state->mode is one of: + + LEN -- ran out of enough output space or enough available input + TYPE -- reached end of block code, inflate() to interpret next block + BAD -- error in block data + + Notes: + + - The maximum input bits used by a length/distance pair is 15 bits for the + length code, 5 bits for the length extra, 15 bits for the distance code, + and 13 bits for the distance extra. This totals 48 bits, or six bytes. + Therefore if strm->avail_in >= 6, then there is enough input to avoid + checking for available input while decoding. + + - The maximum bytes that a single length/distance pair can output is 258 + bytes, which is the maximum length that can be coded. inflate_fast() + requires strm->avail_out >= 258 for each loop to avoid checking for + output space. + */ +void ZLIB_INTERNAL inflate_fast(strm, start) +z_streamp strm; +unsigned start; /* inflate()'s starting value for strm->avail_out */ +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *in; /* local strm->next_in */ + z_const unsigned char FAR *last; /* have enough input while in < last */ + unsigned char FAR *out; /* local strm->next_out */ + unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ + unsigned char FAR *end; /* while out < end, enough space available */ +#ifdef INFLATE_STRICT + unsigned dmax; /* maximum distance from zlib header */ +#endif + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ + unsigned long hold; /* local strm->hold */ + unsigned bits; /* local strm->bits */ + code const FAR *lcode; /* local strm->lencode */ + code const FAR *dcode; /* local strm->distcode */ + unsigned lmask; /* mask for first level of length codes */ + unsigned dmask; /* mask for first level of distance codes */ + code here; /* retrieved table entry */ + unsigned op; /* code bits, operation, extra bits, or */ + /* window position, window bytes to copy */ + unsigned len; /* match length, unused bytes */ + unsigned dist; /* match distance */ + unsigned char FAR *from; /* where to copy match from */ + + /* copy state to local variables */ + state = (struct inflate_state FAR *)strm->state; + in = strm->next_in - OFF; + last = in + (strm->avail_in - 5); + out = strm->next_out - OFF; + beg = out - (start - strm->avail_out); + end = out + (strm->avail_out - 257); +#ifdef INFLATE_STRICT + dmax = state->dmax; +#endif + wsize = state->wsize; + whave = state->whave; + wnext = state->wnext; + window = state->window; + hold = state->hold; + bits = state->bits; + lcode = state->lencode; + dcode = state->distcode; + lmask = (1U << state->lenbits) - 1; + dmask = (1U << state->distbits) - 1; + + /* decode literals and length/distances until end-of-block or not enough + input data or output space */ + do { + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + here = lcode[hold & lmask]; + dolen: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op == 0) { /* literal */ + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + PUP(out) = (unsigned char)(here.val); + } + else if (op & 16) { /* length base */ + len = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (op) { + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + len += (unsigned)hold & ((1U << op) - 1); + hold >>= op; + bits -= op; + } + Tracevv((stderr, "inflate: length %u\n", len)); + if (bits < 15) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + here = dcode[hold & dmask]; + dodist: + op = (unsigned)(here.bits); + hold >>= op; + bits -= op; + op = (unsigned)(here.op); + if (op & 16) { /* distance base */ + dist = (unsigned)(here.val); + op &= 15; /* number of extra bits */ + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + if (bits < op) { + hold += (unsigned long)(PUP(in)) << bits; + bits += 8; + } + } + dist += (unsigned)hold & ((1U << op) - 1); +#ifdef INFLATE_STRICT + if (dist > dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + hold >>= op; + bits -= op; + Tracevv((stderr, "inflate: distance %u\n", dist)); + op = (unsigned)(out - beg); /* max distance in output */ + if (dist > op) { /* see if copy from window */ + op = dist - op; /* distance back in window */ + if (op > whave) { + if (state->sane) { + strm->msg = + (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + if (len <= op - whave) { + do { + PUP(out) = 0; + } while (--len); + continue; + } + len -= op - whave; + do { + PUP(out) = 0; + } while (--op > whave); + if (op == 0) { + from = out - dist; + do { + PUP(out) = PUP(from); + } while (--len); + continue; + } +#endif + } + from = window - OFF; + if (wnext == 0) { /* very common case */ + from += wsize - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + else if (wnext < op) { /* wrap around window */ + from += wsize + wnext - op; + op -= wnext; + if (op < len) { /* some from end of window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = window - OFF; + if (wnext < len) { /* some from start of window */ + op = wnext; + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + } + else { /* contiguous in window */ + from += wnext - op; + if (op < len) { /* some from window */ + len -= op; + do { + PUP(out) = PUP(from); + } while (--op); + from = out - dist; /* rest from output */ + } + } + while (len > 2) { + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + else { + from = out - dist; /* copy direct from output */ + do { /* minimum length is three */ + PUP(out) = PUP(from); + PUP(out) = PUP(from); + PUP(out) = PUP(from); + len -= 3; + } while (len > 2); + if (len) { + PUP(out) = PUP(from); + if (len > 1) + PUP(out) = PUP(from); + } + } + } + else if ((op & 64) == 0) { /* 2nd level distance code */ + here = dcode[here.val + (hold & ((1U << op) - 1))]; + goto dodist; + } + else { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + } + else if ((op & 64) == 0) { /* 2nd level length code */ + here = lcode[here.val + (hold & ((1U << op) - 1))]; + goto dolen; + } + else if (op & 32) { /* end-of-block */ + Tracevv((stderr, "inflate: end of block\n")); + state->mode = TYPE; + break; + } + else { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + } while (in < last && out < end); + + /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ + len = bits >> 3; + in -= len; + bits -= len << 3; + hold &= (1U << bits) - 1; + + /* update state and return */ + strm->next_in = in + OFF; + strm->next_out = out + OFF; + strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); + strm->avail_out = (unsigned)(out < end ? + 257 + (end - out) : 257 - (out - end)); + state->hold = hold; + state->bits = bits; + return; +} + +/* + inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): + - Using bit fields for code structure + - Different op definition to avoid & for extra bits (do & for table bits) + - Three separate decoding do-loops for direct, window, and wnext == 0 + - Special case for distance > 1 copies to do overlapped load and store copy + - Explicit branch predictions (based on measured branch probabilities) + - Deferring match copy and interspersed it with decoding subsequent codes + - Swapping literal/length else + - Swapping window/direct else + - Larger unrolled copy loops (three is about right) + - Moving len -= 3 statement into middle of loop + */ + +#endif /* !ASMINF */ diff --git a/test/zlib/zlib-1.2.8/inffast.h b/test/zlib/zlib-1.2.8/inffast.h new file mode 100644 index 000000000..e5c1aa4ca --- /dev/null +++ b/test/zlib/zlib-1.2.8/inffast.h @@ -0,0 +1,11 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-2003, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/test/zlib/zlib-1.2.8/inffixed.h b/test/zlib/zlib-1.2.8/inffixed.h new file mode 100644 index 000000000..d62832776 --- /dev/null +++ b/test/zlib/zlib-1.2.8/inffixed.h @@ -0,0 +1,94 @@ + /* inffixed.h -- table for decoding fixed codes + * Generated automatically by makefixed(). + */ + + /* WARNING: this file should *not* be used by applications. + It is part of the implementation of this library and is + subject to change. Applications should only use zlib.h. + */ + + static const code lenfix[512] = { + {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, + {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, + {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, + {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, + {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, + {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, + {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, + {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, + {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, + {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, + {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, + {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, + {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, + {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, + {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, + {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, + {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, + {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, + {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, + {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, + {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, + {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, + {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, + {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, + {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, + {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, + {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, + {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, + {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, + {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, + {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, + {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, + {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, + {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, + {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, + {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, + {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, + {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, + {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, + {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, + {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, + {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, + {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, + {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, + {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, + {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, + {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, + {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, + {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, + {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, + {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, + {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, + {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, + {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, + {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, + {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, + {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, + {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, + {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, + {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, + {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, + {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, + {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, + {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, + {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, + {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, + {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, + {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, + {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, + {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, + {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, + {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, + {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, + {0,9,255} + }; + + static const code distfix[32] = { + {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, + {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, + {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, + {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, + {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, + {22,5,193},{64,5,0} + }; diff --git a/test/zlib/zlib-1.2.8/inflate.c b/test/zlib/zlib-1.2.8/inflate.c new file mode 100644 index 000000000..870f89bb4 --- /dev/null +++ b/test/zlib/zlib-1.2.8/inflate.c @@ -0,0 +1,1512 @@ +/* inflate.c -- zlib decompression + * Copyright (C) 1995-2012 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * Change history: + * + * 1.2.beta0 24 Nov 2002 + * - First version -- complete rewrite of inflate to simplify code, avoid + * creation of window when not needed, minimize use of window when it is + * needed, make inffast.c even faster, implement gzip decoding, and to + * improve code readability and style over the previous zlib inflate code + * + * 1.2.beta1 25 Nov 2002 + * - Use pointers for available input and output checking in inffast.c + * - Remove input and output counters in inffast.c + * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 + * - Remove unnecessary second byte pull from length extra in inffast.c + * - Unroll direct copy to three copies per loop in inffast.c + * + * 1.2.beta2 4 Dec 2002 + * - Change external routine names to reduce potential conflicts + * - Correct filename to inffixed.h for fixed tables in inflate.c + * - Make hbuf[] unsigned char to match parameter type in inflate.c + * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) + * to avoid negation problem on Alphas (64 bit) in inflate.c + * + * 1.2.beta3 22 Dec 2002 + * - Add comments on state->bits assertion in inffast.c + * - Add comments on op field in inftrees.h + * - Fix bug in reuse of allocated window after inflateReset() + * - Remove bit fields--back to byte structure for speed + * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths + * - Change post-increments to pre-increments in inflate_fast(), PPC biased? + * - Add compile time option, POSTINC, to use post-increments instead (Intel?) + * - Make MATCH copy in inflate() much faster for when inflate_fast() not used + * - Use local copies of stream next and avail values, as well as local bit + * buffer and bit count in inflate()--for speed when inflate_fast() not used + * + * 1.2.beta4 1 Jan 2003 + * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings + * - Move a comment on output buffer sizes from inffast.c to inflate.c + * - Add comments in inffast.c to introduce the inflate_fast() routine + * - Rearrange window copies in inflate_fast() for speed and simplification + * - Unroll last copy for window match in inflate_fast() + * - Use local copies of window variables in inflate_fast() for speed + * - Pull out common wnext == 0 case for speed in inflate_fast() + * - Make op and len in inflate_fast() unsigned for consistency + * - Add FAR to lcode and dcode declarations in inflate_fast() + * - Simplified bad distance check in inflate_fast() + * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new + * source file infback.c to provide a call-back interface to inflate for + * programs like gzip and unzip -- uses window as output buffer to avoid + * window copying + * + * 1.2.beta5 1 Jan 2003 + * - Improved inflateBack() interface to allow the caller to provide initial + * input in strm. + * - Fixed stored blocks bug in inflateBack() + * + * 1.2.beta6 4 Jan 2003 + * - Added comments in inffast.c on effectiveness of POSTINC + * - Typecasting all around to reduce compiler warnings + * - Changed loops from while (1) or do {} while (1) to for (;;), again to + * make compilers happy + * - Changed type of window in inflateBackInit() to unsigned char * + * + * 1.2.beta7 27 Jan 2003 + * - Changed many types to unsigned or unsigned short to avoid warnings + * - Added inflateCopy() function + * + * 1.2.0 9 Mar 2003 + * - Changed inflateBack() interface to provide separate opaque descriptors + * for the in() and out() functions + * - Changed inflateBack() argument and in_func typedef to swap the length + * and buffer address return values for the input function + * - Check next_in and next_out for Z_NULL on entry to inflate() + * + * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. + */ + +#include "zutil.h" +#include "inftrees.h" +#include "inflate.h" +#include "inffast.h" + +#ifdef MAKEFIXED +# ifndef BUILDFIXED +# define BUILDFIXED +# endif +#endif + +/* function prototypes */ +local void fixedtables OF((struct inflate_state FAR *state)); +local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, + unsigned copy)); +#ifdef BUILDFIXED + void makefixed OF((void)); +#endif +local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, + unsigned len)); + +int ZEXPORT inflateResetKeep(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + strm->total_in = strm->total_out = state->total = 0; + strm->msg = Z_NULL; + if (state->wrap) /* to support ill-conceived Java test suite */ + strm->adler = state->wrap & 1; + state->mode = HEAD; + state->last = 0; + state->havedict = 0; + state->dmax = 32768U; + state->head = Z_NULL; + state->hold = 0; + state->bits = 0; + state->lencode = state->distcode = state->next = state->codes; + state->sane = 1; + state->back = -1; + Tracev((stderr, "inflate: reset\n")); + return Z_OK; +} + +int ZEXPORT inflateReset(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->wsize = 0; + state->whave = 0; + state->wnext = 0; + return inflateResetKeep(strm); +} + +int ZEXPORT inflateReset2(strm, windowBits) +z_streamp strm; +int windowBits; +{ + int wrap; + struct inflate_state FAR *state; + + /* get the state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* extract wrap request from windowBits parameter */ + if (windowBits < 0) { + wrap = 0; + windowBits = -windowBits; + } + else { + wrap = (windowBits >> 4) + 1; +#ifdef GUNZIP + if (windowBits < 48) + windowBits &= 15; +#endif + } + + /* set number of window bits, free window if different */ + if (windowBits && (windowBits < 8 || windowBits > 15)) + return Z_STREAM_ERROR; + if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { + ZFREE(strm, state->window); + state->window = Z_NULL; + } + + /* update state and reset the rest of it */ + state->wrap = wrap; + state->wbits = (unsigned)windowBits; + return inflateReset(strm); +} + +int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) +z_streamp strm; +int windowBits; +const char *version; +int stream_size; +{ + int ret; + struct inflate_state FAR *state; + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != (int)(sizeof(z_stream))) + return Z_VERSION_ERROR; + if (strm == Z_NULL) return Z_STREAM_ERROR; + strm->msg = Z_NULL; /* in case we return an error */ + if (strm->zalloc == (alloc_func)0) { +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; +#endif + } + if (strm->zfree == (free_func)0) +#ifdef Z_SOLO + return Z_STREAM_ERROR; +#else + strm->zfree = zcfree; +#endif + state = (struct inflate_state FAR *) + ZALLOC(strm, 1, sizeof(struct inflate_state)); + if (state == Z_NULL) return Z_MEM_ERROR; + Tracev((stderr, "inflate: allocated\n")); + strm->state = (struct internal_state FAR *)state; + state->window = Z_NULL; + ret = inflateReset2(strm, windowBits); + if (ret != Z_OK) { + ZFREE(strm, state); + strm->state = Z_NULL; + } + return ret; +} + +int ZEXPORT inflateInit_(strm, version, stream_size) +z_streamp strm; +const char *version; +int stream_size; +{ + return inflateInit2_(strm, DEF_WBITS, version, stream_size); +} + +int ZEXPORT inflatePrime(strm, bits, value) +z_streamp strm; +int bits; +int value; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (bits < 0) { + state->hold = 0; + state->bits = 0; + return Z_OK; + } + if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + value &= (1L << bits) - 1; + state->hold += value << state->bits; + state->bits += bits; + return Z_OK; +} + +/* + Return state with length and distance decoding tables and index sizes set to + fixed code decoding. Normally this returns fixed tables from inffixed.h. + If BUILDFIXED is defined, then instead this routine builds the tables the + first time it's called, and returns those tables the first time and + thereafter. This reduces the size of the code by about 2K bytes, in + exchange for a little execution time. However, BUILDFIXED should not be + used for threaded applications, since the rewriting of the tables and virgin + may not be thread-safe. + */ +local void fixedtables(state) +struct inflate_state FAR *state; +{ +#ifdef BUILDFIXED + static int virgin = 1; + static code *lenfix, *distfix; + static code fixed[544]; + + /* build fixed huffman tables if first call (may not be thread safe) */ + if (virgin) { + unsigned sym, bits; + static code *next; + + /* literal/length table */ + sym = 0; + while (sym < 144) state->lens[sym++] = 8; + while (sym < 256) state->lens[sym++] = 9; + while (sym < 280) state->lens[sym++] = 7; + while (sym < 288) state->lens[sym++] = 8; + next = fixed; + lenfix = next; + bits = 9; + inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); + + /* distance table */ + sym = 0; + while (sym < 32) state->lens[sym++] = 5; + distfix = next; + bits = 5; + inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); + + /* do this just once */ + virgin = 0; + } +#else /* !BUILDFIXED */ +# include "inffixed.h" +#endif /* BUILDFIXED */ + state->lencode = lenfix; + state->lenbits = 9; + state->distcode = distfix; + state->distbits = 5; +} + +#ifdef MAKEFIXED +#include + +/* + Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also + defines BUILDFIXED, so the tables are built on the fly. makefixed() writes + those tables to stdout, which would be piped to inffixed.h. A small program + can simply call makefixed to do this: + + void makefixed(void); + + int main(void) + { + makefixed(); + return 0; + } + + Then that can be linked with zlib built with MAKEFIXED defined and run: + + a.out > inffixed.h + */ +void makefixed() +{ + unsigned low, size; + struct inflate_state state; + + fixedtables(&state); + puts(" /* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by makefixed()."); + puts(" */"); + puts(""); + puts(" /* WARNING: this file should *not* be used by applications."); + puts(" It is part of the implementation of this library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + size = 1U << 9; + printf(" static const code lenfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 7) == 0) printf("\n "); + printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, + state.lencode[low].bits, state.lencode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); + size = 1U << 5; + printf("\n static const code distfix[%u] = {", size); + low = 0; + for (;;) { + if ((low % 6) == 0) printf("\n "); + printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, + state.distcode[low].val); + if (++low == size) break; + putchar(','); + } + puts("\n };"); +} +#endif /* MAKEFIXED */ + +/* + Update the window with the last wsize (normally 32K) bytes written before + returning. If window does not exist yet, create it. This is only called + when a window is already in use, or when output has been written during this + inflate call, but the end of the deflate stream has not been reached yet. + It is also called to create a window for dictionary data when a dictionary + is loaded. + + Providing output buffers larger than 32K to inflate() should provide a speed + advantage, since only the last 32K of output is copied to the sliding window + upon return from inflate(), and since all distances after the first 32K of + output will fall in the output data, making match copies simpler and faster. + The advantage may be dependent on the size of the processor's data caches. + */ +local int updatewindow(strm, end, copy) +z_streamp strm; +const Bytef *end; +unsigned copy; +{ + struct inflate_state FAR *state; + unsigned dist; + + state = (struct inflate_state FAR *)strm->state; + + /* if it hasn't been done already, allocate space for the window */ + if (state->window == Z_NULL) { + state->window = (unsigned char FAR *) + ZALLOC(strm, 1U << state->wbits, + sizeof(unsigned char)); + if (state->window == Z_NULL) return 1; + } + + /* if window not in use yet, initialize */ + if (state->wsize == 0) { + state->wsize = 1U << state->wbits; + state->wnext = 0; + state->whave = 0; + } + + /* copy state->wsize or less output bytes into the circular window */ + if (copy >= state->wsize) { + zmemcpy(state->window, end - state->wsize, state->wsize); + state->wnext = 0; + state->whave = state->wsize; + } + else { + dist = state->wsize - state->wnext; + if (dist > copy) dist = copy; + zmemcpy(state->window + state->wnext, end - copy, dist); + copy -= dist; + if (copy) { + zmemcpy(state->window, end - copy, copy); + state->wnext = copy; + state->whave = state->wsize; + } + else { + state->wnext += dist; + if (state->wnext == state->wsize) state->wnext = 0; + if (state->whave < state->wsize) state->whave += dist; + } + } + return 0; +} + +/* Macros for inflate(): */ + +/* check function to use adler32() for zlib or crc32() for gzip */ +#ifdef GUNZIP +# define UPDATE(check, buf, len) \ + (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) +#else +# define UPDATE(check, buf, len) adler32(check, buf, len) +#endif + +/* check macros for header crc */ +#ifdef GUNZIP +# define CRC2(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + check = crc32(check, hbuf, 2); \ + } while (0) + +# define CRC4(check, word) \ + do { \ + hbuf[0] = (unsigned char)(word); \ + hbuf[1] = (unsigned char)((word) >> 8); \ + hbuf[2] = (unsigned char)((word) >> 16); \ + hbuf[3] = (unsigned char)((word) >> 24); \ + check = crc32(check, hbuf, 4); \ + } while (0) +#endif + +/* Load registers with state in inflate() for speed */ +#define LOAD() \ + do { \ + put = strm->next_out; \ + left = strm->avail_out; \ + next = strm->next_in; \ + have = strm->avail_in; \ + hold = state->hold; \ + bits = state->bits; \ + } while (0) + +/* Restore state from registers in inflate() */ +#define RESTORE() \ + do { \ + strm->next_out = put; \ + strm->avail_out = left; \ + strm->next_in = next; \ + strm->avail_in = have; \ + state->hold = hold; \ + state->bits = bits; \ + } while (0) + +/* Clear the input bit accumulator */ +#define INITBITS() \ + do { \ + hold = 0; \ + bits = 0; \ + } while (0) + +/* Get a byte of input into the bit accumulator, or return from inflate() + if there is no input available. */ +#define PULLBYTE() \ + do { \ + if (have == 0) goto inf_leave; \ + have--; \ + hold += (unsigned long)(*next++) << bits; \ + bits += 8; \ + } while (0) + +/* Assure that there are at least n bits in the bit accumulator. If there is + not enough available input to do that, then return from inflate(). */ +#define NEEDBITS(n) \ + do { \ + while (bits < (unsigned)(n)) \ + PULLBYTE(); \ + } while (0) + +/* Return the low n bits of the bit accumulator (n < 16) */ +#define BITS(n) \ + ((unsigned)hold & ((1U << (n)) - 1)) + +/* Remove n bits from the bit accumulator */ +#define DROPBITS(n) \ + do { \ + hold >>= (n); \ + bits -= (unsigned)(n); \ + } while (0) + +/* Remove zero to seven bits as needed to go to a byte boundary */ +#define BYTEBITS() \ + do { \ + hold >>= bits & 7; \ + bits -= bits & 7; \ + } while (0) + +/* + inflate() uses a state machine to process as much input data and generate as + much output data as possible before returning. The state machine is + structured roughly as follows: + + for (;;) switch (state) { + ... + case STATEn: + if (not enough input data or output space to make progress) + return; + ... make progress ... + state = STATEm; + break; + ... + } + + so when inflate() is called again, the same case is attempted again, and + if the appropriate resources are provided, the machine proceeds to the + next state. The NEEDBITS() macro is usually the way the state evaluates + whether it can proceed or should return. NEEDBITS() does the return if + the requested bits are not available. The typical use of the BITS macros + is: + + NEEDBITS(n); + ... do something with BITS(n) ... + DROPBITS(n); + + where NEEDBITS(n) either returns from inflate() if there isn't enough + input left to load n bits into the accumulator, or it continues. BITS(n) + gives the low n bits in the accumulator. When done, DROPBITS(n) drops + the low n bits off the accumulator. INITBITS() clears the accumulator + and sets the number of available bits to zero. BYTEBITS() discards just + enough bits to put the accumulator on a byte boundary. After BYTEBITS() + and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. + + NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return + if there is no input available. The decoding of variable length codes uses + PULLBYTE() directly in order to pull just enough bytes to decode the next + code, and no more. + + Some states loop until they get enough input, making sure that enough + state information is maintained to continue the loop where it left off + if NEEDBITS() returns in the loop. For example, want, need, and keep + would all have to actually be part of the saved state in case NEEDBITS() + returns: + + case STATEw: + while (want < need) { + NEEDBITS(n); + keep[want++] = BITS(n); + DROPBITS(n); + } + state = STATEx; + case STATEx: + + As shown above, if the next state is also the next case, then the break + is omitted. + + A state may also return if there is not enough output space available to + complete that state. Those states are copying stored data, writing a + literal byte, and copying a matching string. + + When returning, a "goto inf_leave" is used to update the total counters, + update the check value, and determine whether any progress has been made + during that inflate() call in order to return the proper return code. + Progress is defined as a change in either strm->avail_in or strm->avail_out. + When there is a window, goto inf_leave will update the window with the last + output written. If a goto inf_leave occurs in the middle of decompression + and there is no window currently, goto inf_leave will create one and copy + output to the window for the next call of inflate(). + + In this implementation, the flush parameter of inflate() only affects the + return code (per zlib.h). inflate() always writes as much as possible to + strm->next_out, given the space available and the provided input--the effect + documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers + the allocation of and copying into a sliding window until necessary, which + provides the effect documented in zlib.h for Z_FINISH when the entire input + stream available. So the only thing the flush parameter actually does is: + when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it + will return Z_BUF_ERROR if it has not reached the end of the stream. + */ + +int ZEXPORT inflate(strm, flush) +z_streamp strm; +int flush; +{ + struct inflate_state FAR *state; + z_const unsigned char FAR *next; /* next input */ + unsigned char FAR *put; /* next output */ + unsigned have, left; /* available input and output */ + unsigned long hold; /* bit buffer */ + unsigned bits; /* bits in bit buffer */ + unsigned in, out; /* save starting available input and output */ + unsigned copy; /* number of stored or match bytes to copy */ + unsigned char FAR *from; /* where to copy match bytes from */ + code here; /* current decoding table entry */ + code last; /* parent table entry */ + unsigned len; /* length to copy for repeats, bits to drop */ + int ret; /* return code */ +#ifdef GUNZIP + unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ +#endif + static const unsigned short order[19] = /* permutation of code lengths */ + {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + + if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0)) + return Z_STREAM_ERROR; + + state = (struct inflate_state FAR *)strm->state; + if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ + LOAD(); + in = have; + out = left; + ret = Z_OK; + for (;;) + switch (state->mode) { + case HEAD: + if (state->wrap == 0) { + state->mode = TYPEDO; + break; + } + NEEDBITS(16); +#ifdef GUNZIP + if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + state->check = crc32(0L, Z_NULL, 0); + CRC2(state->check, hold); + INITBITS(); + state->mode = FLAGS; + break; + } + state->flags = 0; /* expect zlib header */ + if (state->head != Z_NULL) + state->head->done = -1; + if (!(state->wrap & 1) || /* check if zlib header allowed */ +#else + if ( +#endif + ((BITS(8) << 8) + (hold >> 8)) % 31) { + strm->msg = (char *)"incorrect header check"; + state->mode = BAD; + break; + } + if (BITS(4) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + DROPBITS(4); + len = BITS(4) + 8; + if (state->wbits == 0) + state->wbits = len; + else if (len > state->wbits) { + strm->msg = (char *)"invalid window size"; + state->mode = BAD; + break; + } + state->dmax = 1U << len; + Tracev((stderr, "inflate: zlib header ok\n")); + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = hold & 0x200 ? DICTID : TYPE; + INITBITS(); + break; +#ifdef GUNZIP + case FLAGS: + NEEDBITS(16); + state->flags = (int)(hold); + if ((state->flags & 0xff) != Z_DEFLATED) { + strm->msg = (char *)"unknown compression method"; + state->mode = BAD; + break; + } + if (state->flags & 0xe000) { + strm->msg = (char *)"unknown header flags set"; + state->mode = BAD; + break; + } + if (state->head != Z_NULL) + state->head->text = (int)((hold >> 8) & 1); + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = TIME; + case TIME: + NEEDBITS(32); + if (state->head != Z_NULL) + state->head->time = hold; + if (state->flags & 0x0200) CRC4(state->check, hold); + INITBITS(); + state->mode = OS; + case OS: + NEEDBITS(16); + if (state->head != Z_NULL) { + state->head->xflags = (int)(hold & 0xff); + state->head->os = (int)(hold >> 8); + } + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + state->mode = EXLEN; + case EXLEN: + if (state->flags & 0x0400) { + NEEDBITS(16); + state->length = (unsigned)(hold); + if (state->head != Z_NULL) + state->head->extra_len = (unsigned)hold; + if (state->flags & 0x0200) CRC2(state->check, hold); + INITBITS(); + } + else if (state->head != Z_NULL) + state->head->extra = Z_NULL; + state->mode = EXTRA; + case EXTRA: + if (state->flags & 0x0400) { + copy = state->length; + if (copy > have) copy = have; + if (copy) { + if (state->head != Z_NULL && + state->head->extra != Z_NULL) { + len = state->head->extra_len - state->length; + zmemcpy(state->head->extra + len, next, + len + copy > state->head->extra_max ? + state->head->extra_max - len : copy); + } + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + state->length -= copy; + } + if (state->length) goto inf_leave; + } + state->length = 0; + state->mode = NAME; + case NAME: + if (state->flags & 0x0800) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->name != Z_NULL && + state->length < state->head->name_max) + state->head->name[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->name = Z_NULL; + state->length = 0; + state->mode = COMMENT; + case COMMENT: + if (state->flags & 0x1000) { + if (have == 0) goto inf_leave; + copy = 0; + do { + len = (unsigned)(next[copy++]); + if (state->head != Z_NULL && + state->head->comment != Z_NULL && + state->length < state->head->comm_max) + state->head->comment[state->length++] = len; + } while (len && copy < have); + if (state->flags & 0x0200) + state->check = crc32(state->check, next, copy); + have -= copy; + next += copy; + if (len) goto inf_leave; + } + else if (state->head != Z_NULL) + state->head->comment = Z_NULL; + state->mode = HCRC; + case HCRC: + if (state->flags & 0x0200) { + NEEDBITS(16); + if (hold != (state->check & 0xffff)) { + strm->msg = (char *)"header crc mismatch"; + state->mode = BAD; + break; + } + INITBITS(); + } + if (state->head != Z_NULL) { + state->head->hcrc = (int)((state->flags >> 9) & 1); + state->head->done = 1; + } + strm->adler = state->check = crc32(0L, Z_NULL, 0); + state->mode = TYPE; + break; +#endif + case DICTID: + NEEDBITS(32); + strm->adler = state->check = ZSWAP32(hold); + INITBITS(); + state->mode = DICT; + case DICT: + if (state->havedict == 0) { + RESTORE(); + return Z_NEED_DICT; + } + strm->adler = state->check = adler32(0L, Z_NULL, 0); + state->mode = TYPE; + case TYPE: + if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; + case TYPEDO: + if (state->last) { + BYTEBITS(); + state->mode = CHECK; + break; + } + NEEDBITS(3); + state->last = BITS(1); + DROPBITS(1); + switch (BITS(2)) { + case 0: /* stored block */ + Tracev((stderr, "inflate: stored block%s\n", + state->last ? " (last)" : "")); + state->mode = STORED; + break; + case 1: /* fixed block */ + fixedtables(state); + Tracev((stderr, "inflate: fixed codes block%s\n", + state->last ? " (last)" : "")); + state->mode = LEN_; /* decode codes */ + if (flush == Z_TREES) { + DROPBITS(2); + goto inf_leave; + } + break; + case 2: /* dynamic block */ + Tracev((stderr, "inflate: dynamic codes block%s\n", + state->last ? " (last)" : "")); + state->mode = TABLE; + break; + case 3: + strm->msg = (char *)"invalid block type"; + state->mode = BAD; + } + DROPBITS(2); + break; + case STORED: + BYTEBITS(); /* go to byte boundary */ + NEEDBITS(32); + if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { + strm->msg = (char *)"invalid stored block lengths"; + state->mode = BAD; + break; + } + state->length = (unsigned)hold & 0xffff; + Tracev((stderr, "inflate: stored length %u\n", + state->length)); + INITBITS(); + state->mode = COPY_; + if (flush == Z_TREES) goto inf_leave; + case COPY_: + state->mode = COPY; + case COPY: + copy = state->length; + if (copy) { + if (copy > have) copy = have; + if (copy > left) copy = left; + if (copy == 0) goto inf_leave; + zmemcpy(put, next, copy); + have -= copy; + next += copy; + left -= copy; + put += copy; + state->length -= copy; + break; + } + Tracev((stderr, "inflate: stored end\n")); + state->mode = TYPE; + break; + case TABLE: + NEEDBITS(14); + state->nlen = BITS(5) + 257; + DROPBITS(5); + state->ndist = BITS(5) + 1; + DROPBITS(5); + state->ncode = BITS(4) + 4; + DROPBITS(4); +#ifndef PKZIP_BUG_WORKAROUND + if (state->nlen > 286 || state->ndist > 30) { + strm->msg = (char *)"too many length or distance symbols"; + state->mode = BAD; + break; + } +#endif + Tracev((stderr, "inflate: table sizes ok\n")); + state->have = 0; + state->mode = LENLENS; + case LENLENS: + while (state->have < state->ncode) { + NEEDBITS(3); + state->lens[order[state->have++]] = (unsigned short)BITS(3); + DROPBITS(3); + } + while (state->have < 19) + state->lens[order[state->have++]] = 0; + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 7; + ret = inflate_table(CODES, state->lens, 19, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid code lengths set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: code lengths ok\n")); + state->have = 0; + state->mode = CODELENS; + case CODELENS: + while (state->have < state->nlen + state->ndist) { + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.val < 16) { + DROPBITS(here.bits); + state->lens[state->have++] = here.val; + } + else { + if (here.val == 16) { + NEEDBITS(here.bits + 2); + DROPBITS(here.bits); + if (state->have == 0) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + len = state->lens[state->have - 1]; + copy = 3 + BITS(2); + DROPBITS(2); + } + else if (here.val == 17) { + NEEDBITS(here.bits + 3); + DROPBITS(here.bits); + len = 0; + copy = 3 + BITS(3); + DROPBITS(3); + } + else { + NEEDBITS(here.bits + 7); + DROPBITS(here.bits); + len = 0; + copy = 11 + BITS(7); + DROPBITS(7); + } + if (state->have + copy > state->nlen + state->ndist) { + strm->msg = (char *)"invalid bit length repeat"; + state->mode = BAD; + break; + } + while (copy--) + state->lens[state->have++] = (unsigned short)len; + } + } + + /* handle error breaks in while */ + if (state->mode == BAD) break; + + /* check for end-of-block code (better have one) */ + if (state->lens[256] == 0) { + strm->msg = (char *)"invalid code -- missing end-of-block"; + state->mode = BAD; + break; + } + + /* build code tables -- note: do not change the lenbits or distbits + values here (9 and 6) without reading the comments in inftrees.h + concerning the ENOUGH constants, which depend on those values */ + state->next = state->codes; + state->lencode = (const code FAR *)(state->next); + state->lenbits = 9; + ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), + &(state->lenbits), state->work); + if (ret) { + strm->msg = (char *)"invalid literal/lengths set"; + state->mode = BAD; + break; + } + state->distcode = (const code FAR *)(state->next); + state->distbits = 6; + ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, + &(state->next), &(state->distbits), state->work); + if (ret) { + strm->msg = (char *)"invalid distances set"; + state->mode = BAD; + break; + } + Tracev((stderr, "inflate: codes ok\n")); + state->mode = LEN_; + if (flush == Z_TREES) goto inf_leave; + case LEN_: + state->mode = LEN; + case LEN: + if (have >= 6 && left >= 258) { + RESTORE(); + inflate_fast(strm, out); + LOAD(); + if (state->mode == TYPE) + state->back = -1; + break; + } + state->back = 0; + for (;;) { + here = state->lencode[BITS(state->lenbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if (here.op && (here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->lencode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + state->length = (unsigned)here.val; + if ((int)(here.op) == 0) { + Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", here.val)); + state->mode = LIT; + break; + } + if (here.op & 32) { + Tracevv((stderr, "inflate: end of block\n")); + state->back = -1; + state->mode = TYPE; + break; + } + if (here.op & 64) { + strm->msg = (char *)"invalid literal/length code"; + state->mode = BAD; + break; + } + state->extra = (unsigned)(here.op) & 15; + state->mode = LENEXT; + case LENEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->length += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } + Tracevv((stderr, "inflate: length %u\n", state->length)); + state->was = state->length; + state->mode = DIST; + case DIST: + for (;;) { + here = state->distcode[BITS(state->distbits)]; + if ((unsigned)(here.bits) <= bits) break; + PULLBYTE(); + } + if ((here.op & 0xf0) == 0) { + last = here; + for (;;) { + here = state->distcode[last.val + + (BITS(last.bits + last.op) >> last.bits)]; + if ((unsigned)(last.bits + here.bits) <= bits) break; + PULLBYTE(); + } + DROPBITS(last.bits); + state->back += last.bits; + } + DROPBITS(here.bits); + state->back += here.bits; + if (here.op & 64) { + strm->msg = (char *)"invalid distance code"; + state->mode = BAD; + break; + } + state->offset = (unsigned)here.val; + state->extra = (unsigned)(here.op) & 15; + state->mode = DISTEXT; + case DISTEXT: + if (state->extra) { + NEEDBITS(state->extra); + state->offset += BITS(state->extra); + DROPBITS(state->extra); + state->back += state->extra; + } +#ifdef INFLATE_STRICT + if (state->offset > state->dmax) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#endif + Tracevv((stderr, "inflate: distance %u\n", state->offset)); + state->mode = MATCH; + case MATCH: + if (left == 0) goto inf_leave; + copy = out - left; + if (state->offset > copy) { /* copy from window */ + copy = state->offset - copy; + if (copy > state->whave) { + if (state->sane) { + strm->msg = (char *)"invalid distance too far back"; + state->mode = BAD; + break; + } +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + Trace((stderr, "inflate.c too far\n")); + copy -= state->whave; + if (copy > state->length) copy = state->length; + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = 0; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; +#endif + } + if (copy > state->wnext) { + copy -= state->wnext; + from = state->window + (state->wsize - copy); + } + else + from = state->window + (state->wnext - copy); + if (copy > state->length) copy = state->length; + } + else { /* copy from output */ + from = put - state->offset; + copy = state->length; + } + if (copy > left) copy = left; + left -= copy; + state->length -= copy; + do { + *put++ = *from++; + } while (--copy); + if (state->length == 0) state->mode = LEN; + break; + case LIT: + if (left == 0) goto inf_leave; + *put++ = (unsigned char)(state->length); + left--; + state->mode = LEN; + break; + case CHECK: + if (state->wrap) { + NEEDBITS(32); + out -= left; + strm->total_out += out; + state->total += out; + if (out) + strm->adler = state->check = + UPDATE(state->check, put - out, out); + out = left; + if (( +#ifdef GUNZIP + state->flags ? hold : +#endif + ZSWAP32(hold)) != state->check) { + strm->msg = (char *)"incorrect data check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: check matches trailer\n")); + } +#ifdef GUNZIP + state->mode = LENGTH; + case LENGTH: + if (state->wrap && state->flags) { + NEEDBITS(32); + if (hold != (state->total & 0xffffffffUL)) { + strm->msg = (char *)"incorrect length check"; + state->mode = BAD; + break; + } + INITBITS(); + Tracev((stderr, "inflate: length matches trailer\n")); + } +#endif + state->mode = DONE; + case DONE: + ret = Z_STREAM_END; + goto inf_leave; + case BAD: + ret = Z_DATA_ERROR; + goto inf_leave; + case MEM: + return Z_MEM_ERROR; + case SYNC: + default: + return Z_STREAM_ERROR; + } + + /* + Return from inflate(), updating the total counts and the check value. + If there was no progress during the inflate() call, return a buffer + error. Call updatewindow() to create and/or update the window state. + Note: a memory error from inflate() is non-recoverable. + */ + inf_leave: + RESTORE(); + if (state->wsize || (out != strm->avail_out && state->mode < BAD && + (state->mode < CHECK || flush != Z_FINISH))) + if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { + state->mode = MEM; + return Z_MEM_ERROR; + } + in -= strm->avail_in; + out -= strm->avail_out; + strm->total_in += in; + strm->total_out += out; + state->total += out; + if (state->wrap && out) + strm->adler = state->check = + UPDATE(state->check, strm->next_out - out, out); + strm->data_type = state->bits + (state->last ? 64 : 0) + + (state->mode == TYPE ? 128 : 0) + + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); + if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) + ret = Z_BUF_ERROR; + return ret; +} + +int ZEXPORT inflateEnd(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->window != Z_NULL) ZFREE(strm, state->window); + ZFREE(strm, strm->state); + strm->state = Z_NULL; + Tracev((stderr, "inflate: end\n")); + return Z_OK; +} + +int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) +z_streamp strm; +Bytef *dictionary; +uInt *dictLength; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + + /* copy dictionary */ + if (state->whave && dictionary != Z_NULL) { + zmemcpy(dictionary, state->window + state->wnext, + state->whave - state->wnext); + zmemcpy(dictionary + state->whave - state->wnext, + state->window, state->wnext); + } + if (dictLength != Z_NULL) + *dictLength = state->whave; + return Z_OK; +} + +int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) +z_streamp strm; +const Bytef *dictionary; +uInt dictLength; +{ + struct inflate_state FAR *state; + unsigned long dictid; + int ret; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (state->wrap != 0 && state->mode != DICT) + return Z_STREAM_ERROR; + + /* check for correct dictionary identifier */ + if (state->mode == DICT) { + dictid = adler32(0L, Z_NULL, 0); + dictid = adler32(dictid, dictionary, dictLength); + if (dictid != state->check) + return Z_DATA_ERROR; + } + + /* copy dictionary to window using updatewindow(), which will amend the + existing dictionary if appropriate */ + ret = updatewindow(strm, dictionary + dictLength, dictLength); + if (ret) { + state->mode = MEM; + return Z_MEM_ERROR; + } + state->havedict = 1; + Tracev((stderr, "inflate: dictionary set\n")); + return Z_OK; +} + +int ZEXPORT inflateGetHeader(strm, head) +z_streamp strm; +gz_headerp head; +{ + struct inflate_state FAR *state; + + /* check state */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; + + /* save header structure */ + state->head = head; + head->done = 0; + return Z_OK; +} + +/* + Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found + or when out of input. When called, *have is the number of pattern bytes + found in order so far, in 0..3. On return *have is updated to the new + state. If on return *have equals four, then the pattern was found and the + return value is how many bytes were read including the last byte of the + pattern. If *have is less than four, then the pattern has not been found + yet and the return value is len. In the latter case, syncsearch() can be + called again with more data and the *have state. *have is initialized to + zero for the first call. + */ +local unsigned syncsearch(have, buf, len) +unsigned FAR *have; +const unsigned char FAR *buf; +unsigned len; +{ + unsigned got; + unsigned next; + + got = *have; + next = 0; + while (next < len && got < 4) { + if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) + got++; + else if (buf[next]) + got = 0; + else + got = 4 - got; + next++; + } + *have = got; + return next; +} + +int ZEXPORT inflateSync(strm) +z_streamp strm; +{ + unsigned len; /* number of bytes to look at or looked at */ + unsigned long in, out; /* temporary to save total_in and total_out */ + unsigned char buf[4]; /* to restore bit buffer to byte string */ + struct inflate_state FAR *state; + + /* check parameters */ + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; + + /* if first time, start search in bit buffer */ + if (state->mode != SYNC) { + state->mode = SYNC; + state->hold <<= state->bits & 7; + state->bits -= state->bits & 7; + len = 0; + while (state->bits >= 8) { + buf[len++] = (unsigned char)(state->hold); + state->hold >>= 8; + state->bits -= 8; + } + state->have = 0; + syncsearch(&(state->have), buf, len); + } + + /* search available input */ + len = syncsearch(&(state->have), strm->next_in, strm->avail_in); + strm->avail_in -= len; + strm->next_in += len; + strm->total_in += len; + + /* return no joy or set up to restart inflate() on a new block */ + if (state->have != 4) return Z_DATA_ERROR; + in = strm->total_in; out = strm->total_out; + inflateReset(strm); + strm->total_in = in; strm->total_out = out; + state->mode = TYPE; + return Z_OK; +} + +/* + Returns true if inflate is currently at the end of a block generated by + Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + implementation to provide an additional safety check. PPP uses + Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored + block. When decompressing, PPP checks that at the end of input packet, + inflate is waiting for these length bytes. + */ +int ZEXPORT inflateSyncPoint(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + return state->mode == STORED && state->bits == 0; +} + +int ZEXPORT inflateCopy(dest, source) +z_streamp dest; +z_streamp source; +{ + struct inflate_state FAR *state; + struct inflate_state FAR *copy; + unsigned char FAR *window; + unsigned wsize; + + /* check input */ + if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || + source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)source->state; + + /* allocate space */ + copy = (struct inflate_state FAR *) + ZALLOC(source, 1, sizeof(struct inflate_state)); + if (copy == Z_NULL) return Z_MEM_ERROR; + window = Z_NULL; + if (state->window != Z_NULL) { + window = (unsigned char FAR *) + ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); + if (window == Z_NULL) { + ZFREE(source, copy); + return Z_MEM_ERROR; + } + } + + /* copy state */ + zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); + zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); + if (state->lencode >= state->codes && + state->lencode <= state->codes + ENOUGH - 1) { + copy->lencode = copy->codes + (state->lencode - state->codes); + copy->distcode = copy->codes + (state->distcode - state->codes); + } + copy->next = copy->codes + (state->next - state->codes); + if (window != Z_NULL) { + wsize = 1U << state->wbits; + zmemcpy(window, state->window, wsize); + } + copy->window = window; + dest->state = (struct internal_state FAR *)copy; + return Z_OK; +} + +int ZEXPORT inflateUndermine(strm, subvert) +z_streamp strm; +int subvert; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + state->sane = !subvert; +#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + return Z_OK; +#else + state->sane = 1; + return Z_DATA_ERROR; +#endif +} + +long ZEXPORT inflateMark(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + + if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16; + state = (struct inflate_state FAR *)strm->state; + return ((long)(state->back) << 16) + + (state->mode == COPY ? state->length : + (state->mode == MATCH ? state->was - state->length : 0)); +} diff --git a/test/zlib/zlib-1.2.8/inflate.h b/test/zlib/zlib-1.2.8/inflate.h new file mode 100644 index 000000000..95f4986d4 --- /dev/null +++ b/test/zlib/zlib-1.2.8/inflate.h @@ -0,0 +1,122 @@ +/* inflate.h -- internal inflate state definition + * Copyright (C) 1995-2009 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* define NO_GZIP when compiling if you want to disable gzip header and + trailer decoding by inflate(). NO_GZIP would be used to avoid linking in + the crc code when it is not needed. For shared libraries, gzip decoding + should be left enabled. */ +#ifndef NO_GZIP +# define GUNZIP +#endif + +/* Possible inflate modes between inflate() calls */ +typedef enum { + HEAD, /* i: waiting for magic header */ + FLAGS, /* i: waiting for method and flags (gzip) */ + TIME, /* i: waiting for modification time (gzip) */ + OS, /* i: waiting for extra flags and operating system (gzip) */ + EXLEN, /* i: waiting for extra length (gzip) */ + EXTRA, /* i: waiting for extra bytes (gzip) */ + NAME, /* i: waiting for end of file name (gzip) */ + COMMENT, /* i: waiting for end of comment (gzip) */ + HCRC, /* i: waiting for header crc (gzip) */ + DICTID, /* i: waiting for dictionary check value */ + DICT, /* waiting for inflateSetDictionary() call */ + TYPE, /* i: waiting for type bits, including last-flag bit */ + TYPEDO, /* i: same, but skip check to exit inflate on new block */ + STORED, /* i: waiting for stored size (length and complement) */ + COPY_, /* i/o: same as COPY below, but only first time in */ + COPY, /* i/o: waiting for input or output to copy stored block */ + TABLE, /* i: waiting for dynamic block table lengths */ + LENLENS, /* i: waiting for code length code lengths */ + CODELENS, /* i: waiting for length/lit and distance code lengths */ + LEN_, /* i: same as LEN below, but only first time in */ + LEN, /* i: waiting for length/lit/eob code */ + LENEXT, /* i: waiting for length extra bits */ + DIST, /* i: waiting for distance code */ + DISTEXT, /* i: waiting for distance extra bits */ + MATCH, /* o: waiting for output space to copy string */ + LIT, /* o: waiting for output space to write literal */ + CHECK, /* i: waiting for 32-bit check value */ + LENGTH, /* i: waiting for 32-bit length (gzip) */ + DONE, /* finished check, done -- remain here until reset */ + BAD, /* got a data error -- remain here until reset */ + MEM, /* got an inflate() memory error -- remain here until reset */ + SYNC /* looking for synchronization bytes to restart inflate() */ +} inflate_mode; + +/* + State transitions between above modes - + + (most modes can go to BAD or MEM on error -- not shown for clarity) + + Process header: + HEAD -> (gzip) or (zlib) or (raw) + (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> + HCRC -> TYPE + (zlib) -> DICTID or TYPE + DICTID -> DICT -> TYPE + (raw) -> TYPEDO + Read deflate blocks: + TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK + STORED -> COPY_ -> COPY -> TYPE + TABLE -> LENLENS -> CODELENS -> LEN_ + LEN_ -> LEN + Read deflate codes in fixed or dynamic block: + LEN -> LENEXT or LIT or TYPE + LENEXT -> DIST -> DISTEXT -> MATCH -> LEN + LIT -> LEN + Process trailer: + CHECK -> LENGTH -> DONE + */ + +/* state maintained between inflate() calls. Approximately 10K bytes. */ +struct inflate_state { + inflate_mode mode; /* current inflate mode */ + int last; /* true if processing last block */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int havedict; /* true if dictionary provided */ + int flags; /* gzip header method and flags (0 if zlib) */ + unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ + unsigned long check; /* protected copy of check value */ + unsigned long total; /* protected copy of output count */ + gz_headerp head; /* where to save gzip header information */ + /* sliding window */ + unsigned wbits; /* log base 2 of requested window size */ + unsigned wsize; /* window size or zero if not using window */ + unsigned whave; /* valid bytes in the window */ + unsigned wnext; /* window write index */ + unsigned char FAR *window; /* allocated sliding window, if needed */ + /* bit accumulator */ + unsigned long hold; /* input bit accumulator */ + unsigned bits; /* number of bits in "in" */ + /* for string and stored block copying */ + unsigned length; /* literal or length of data to copy */ + unsigned offset; /* distance back to copy string from */ + /* for table and code decoding */ + unsigned extra; /* extra bits needed */ + /* fixed and dynamic code tables */ + code const FAR *lencode; /* starting table for length/literal codes */ + code const FAR *distcode; /* starting table for distance codes */ + unsigned lenbits; /* index bits for lencode */ + unsigned distbits; /* index bits for distcode */ + /* dynamic table building */ + unsigned ncode; /* number of code length code lengths */ + unsigned nlen; /* number of length code lengths */ + unsigned ndist; /* number of distance code lengths */ + unsigned have; /* number of code lengths in lens[] */ + code FAR *next; /* next available space in codes[] */ + unsigned short lens[320]; /* temporary storage for code lengths */ + unsigned short work[288]; /* work area for code table building */ + code codes[ENOUGH]; /* space for code tables */ + int sane; /* if false, allow invalid distance too far */ + int back; /* bits back of last unprocessed length/lit */ + unsigned was; /* initial length of match */ +}; diff --git a/test/zlib/zlib-1.2.8/inftrees.c b/test/zlib/zlib-1.2.8/inftrees.c new file mode 100644 index 000000000..44d89cf24 --- /dev/null +++ b/test/zlib/zlib-1.2.8/inftrees.c @@ -0,0 +1,306 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-2013 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" + +#define MAXBITS 15 + +const char inflate_copyright[] = + " inflate 1.2.8 Copyright 1995-2013 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* + Build a set of tables to decode the provided canonical Huffman code. + The code lengths are lens[0..codes-1]. The result starts at *table, + whose indices are 0..2^bits-1. work is a writable array of at least + lens shorts, which is used as a work area. type is the type of code + to be generated, CODES, LENS, or DISTS. On return, zero is success, + -1 is an invalid code, and +1 means that ENOUGH isn't enough. table + on return points to the next available entry's address. bits is the + requested root table index bits, and on return it is the actual root + table index bits. It will differ if the request is greater than the + longest code or if it is less than the shortest code. + */ +int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) +codetype type; +unsigned short FAR *lens; +unsigned codes; +code FAR * FAR *table; +unsigned FAR *bits; +unsigned short FAR *work; +{ + unsigned len; /* a code's length in bits */ + unsigned sym; /* index of code symbols */ + unsigned min, max; /* minimum and maximum code lengths */ + unsigned root; /* number of index bits for root table */ + unsigned curr; /* number of index bits for current table */ + unsigned drop; /* code bits to drop for sub-table */ + int left; /* number of prefix codes available */ + unsigned used; /* code entries in table used */ + unsigned huff; /* Huffman code */ + unsigned incr; /* for incrementing code, index */ + unsigned fill; /* index for replicating entries */ + unsigned low; /* low bits for current root entry */ + unsigned mask; /* mask for low root bits */ + code here; /* table entry for duplication */ + code FAR *next; /* next available space in table */ + const unsigned short FAR *base; /* base value table to use */ + const unsigned short FAR *extra; /* extra bits table to use */ + int end; /* use base and extra for symbol > end */ + unsigned short count[MAXBITS+1]; /* number of codes of each length */ + unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ + static const unsigned short lbase[31] = { /* Length codes 257..285 base */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const unsigned short lext[31] = { /* Length codes 257..285 extra */ + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78}; + static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577, 0, 0}; + static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ + 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, + 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, + 28, 28, 29, 29, 64, 64}; + + /* + Process a set of code lengths to create a canonical Huffman code. The + code lengths are lens[0..codes-1]. Each length corresponds to the + symbols 0..codes-1. The Huffman code is generated by first sorting the + symbols by length from short to long, and retaining the symbol order + for codes with equal lengths. Then the code starts with all zero bits + for the first code of the shortest length, and the codes are integer + increments for the same length, and zeros are appended as the length + increases. For the deflate format, these bits are stored backwards + from their more natural integer increment ordering, and so when the + decoding tables are built in the large loop below, the integer codes + are incremented backwards. + + This routine assumes, but does not check, that all of the entries in + lens[] are in the range 0..MAXBITS. The caller must assure this. + 1..MAXBITS is interpreted as that code length. zero means that that + symbol does not occur in this code. + + The codes are sorted by computing a count of codes for each length, + creating from that a table of starting indices for each length in the + sorted table, and then entering the symbols in order in the sorted + table. The sorted table is work[], with that space being provided by + the caller. + + The length counts are used for other purposes as well, i.e. finding + the minimum and maximum length codes, determining if there are any + codes at all, checking for a valid set of lengths, and looking ahead + at length counts to determine sub-table sizes when building the + decoding tables. + */ + + /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ + for (len = 0; len <= MAXBITS; len++) + count[len] = 0; + for (sym = 0; sym < codes; sym++) + count[lens[sym]]++; + + /* bound code lengths, force root to be within code lengths */ + root = *bits; + for (max = MAXBITS; max >= 1; max--) + if (count[max] != 0) break; + if (root > max) root = max; + if (max == 0) { /* no symbols to code at all */ + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)1; + here.val = (unsigned short)0; + *(*table)++ = here; /* make a table to force an error */ + *(*table)++ = here; + *bits = 1; + return 0; /* no symbols, but wait for decoding to report error */ + } + for (min = 1; min < max; min++) + if (count[min] != 0) break; + if (root < min) root = min; + + /* check for an over-subscribed or incomplete set of lengths */ + left = 1; + for (len = 1; len <= MAXBITS; len++) { + left <<= 1; + left -= count[len]; + if (left < 0) return -1; /* over-subscribed */ + } + if (left > 0 && (type == CODES || max != 1)) + return -1; /* incomplete set */ + + /* generate offsets into symbol table for each length for sorting */ + offs[1] = 0; + for (len = 1; len < MAXBITS; len++) + offs[len + 1] = offs[len] + count[len]; + + /* sort symbols by length, by symbol order within each length */ + for (sym = 0; sym < codes; sym++) + if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; + + /* + Create and fill in decoding tables. In this loop, the table being + filled is at next and has curr index bits. The code being used is huff + with length len. That code is converted to an index by dropping drop + bits off of the bottom. For codes where len is less than drop + curr, + those top drop + curr - len bits are incremented through all values to + fill the table with replicated entries. + + root is the number of index bits for the root table. When len exceeds + root, sub-tables are created pointed to by the root entry with an index + of the low root bits of huff. This is saved in low to check for when a + new sub-table should be started. drop is zero when the root table is + being filled, and drop is root when sub-tables are being filled. + + When a new sub-table is needed, it is necessary to look ahead in the + code lengths to determine what size sub-table is needed. The length + counts are used for this, and so count[] is decremented as codes are + entered in the tables. + + used keeps track of how many table entries have been allocated from the + provided *table space. It is checked for LENS and DIST tables against + the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in + the initial root table size constants. See the comments in inftrees.h + for more information. + + sym increments through all symbols, and the loop terminates when + all codes of length max, i.e. all codes, have been processed. This + routine permits incomplete codes, so another loop after this one fills + in the rest of the decoding tables with invalid code markers. + */ + + /* set up for code type */ + switch (type) { + case CODES: + base = extra = work; /* dummy value--not used */ + end = 19; + break; + case LENS: + base = lbase; + base -= 257; + extra = lext; + extra -= 257; + end = 256; + break; + default: /* DISTS */ + base = dbase; + extra = dext; + end = -1; + } + + /* initialize state for loop */ + huff = 0; /* starting code */ + sym = 0; /* starting code symbol */ + len = min; /* starting code length */ + next = *table; /* current table to fill in */ + curr = root; /* current table index bits */ + drop = 0; /* current bits to drop from code for index */ + low = (unsigned)(-1); /* trigger new sub-table when len > root */ + used = 1U << root; /* use root table entries */ + mask = used - 1; /* mask for comparing low */ + + /* check available table space */ + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* process all codes and make table entries */ + for (;;) { + /* create table entry */ + here.bits = (unsigned char)(len - drop); + if ((int)(work[sym]) < end) { + here.op = (unsigned char)0; + here.val = work[sym]; + } + else if ((int)(work[sym]) > end) { + here.op = (unsigned char)(extra[work[sym]]); + here.val = base[work[sym]]; + } + else { + here.op = (unsigned char)(32 + 64); /* end of block */ + here.val = 0; + } + + /* replicate for those indices with low len bits equal to huff */ + incr = 1U << (len - drop); + fill = 1U << curr; + min = fill; /* save offset to next table */ + do { + fill -= incr; + next[(huff >> drop) + fill] = here; + } while (fill != 0); + + /* backwards increment the len-bit code huff */ + incr = 1U << (len - 1); + while (huff & incr) + incr >>= 1; + if (incr != 0) { + huff &= incr - 1; + huff += incr; + } + else + huff = 0; + + /* go to next symbol, update count, len */ + sym++; + if (--(count[len]) == 0) { + if (len == max) break; + len = lens[work[sym]]; + } + + /* create new sub-table if needed */ + if (len > root && (huff & mask) != low) { + /* if first time, transition to sub-tables */ + if (drop == 0) + drop = root; + + /* increment past last table */ + next += min; /* here min is 1 << curr */ + + /* determine length of next table */ + curr = len - drop; + left = (int)(1 << curr); + while (curr + drop < max) { + left -= count[curr + drop]; + if (left <= 0) break; + curr++; + left <<= 1; + } + + /* check for enough space */ + used += 1U << curr; + if ((type == LENS && used > ENOUGH_LENS) || + (type == DISTS && used > ENOUGH_DISTS)) + return 1; + + /* point entry in root table to sub-table */ + low = huff & mask; + (*table)[low].op = (unsigned char)curr; + (*table)[low].bits = (unsigned char)root; + (*table)[low].val = (unsigned short)(next - *table); + } + } + + /* fill in remaining table entry if code is incomplete (guaranteed to have + at most one remaining entry, since if the code is incomplete, the + maximum code length that was allowed to get this far is one bit) */ + if (huff != 0) { + here.op = (unsigned char)64; /* invalid code marker */ + here.bits = (unsigned char)(len - drop); + here.val = (unsigned short)0; + next[huff] = here; + } + + /* set return parameters */ + *table += used; + *bits = root; + return 0; +} diff --git a/test/zlib/zlib-1.2.8/inftrees.h b/test/zlib/zlib-1.2.8/inftrees.h new file mode 100644 index 000000000..baa53a0b1 --- /dev/null +++ b/test/zlib/zlib-1.2.8/inftrees.h @@ -0,0 +1,62 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-2005, 2010 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Structure for decoding tables. Each entry provides either the + information needed to do the operation requested by the code that + indexed that table entry, or it provides a pointer to another + table that indexes more bits of the code. op indicates whether + the entry is a pointer to another table, a literal, a length or + distance, an end-of-block, or an invalid code. For a table + pointer, the low four bits of op is the number of index bits of + that table. For a length or distance, the low four bits of op + is the number of extra bits to get after the code. bits is + the number of bits in this code or part of the code to drop off + of the bit buffer. val is the actual byte to output in the case + of a literal, the base length or distance, or the offset from + the current table to the next table. Each entry is four bytes. */ +typedef struct { + unsigned char op; /* operation, extra bits, table bits */ + unsigned char bits; /* bits in this part of the code */ + unsigned short val; /* offset in table or code value */ +} code; + +/* op values as set by inflate_table(): + 00000000 - literal + 0000tttt - table link, tttt != 0 is the number of table index bits + 0001eeee - length or distance, eeee is the number of extra bits + 01100000 - end of block + 01000000 - invalid code + */ + +/* Maximum size of the dynamic table. The maximum number of code structures is + 1444, which is the sum of 852 for literal/length codes and 592 for distance + codes. These values were found by exhaustive searches using the program + examples/enough.c found in the zlib distribtution. The arguments to that + program are the number of symbols, the initial root table size, and the + maximum bit length of a code. "enough 286 9 15" for literal/length codes + returns returns 852, and "enough 30 6 15" for distance codes returns 592. + The initial root table size (9 or 6) is found in the fifth argument of the + inflate_table() calls in inflate.c and infback.c. If the root table size is + changed, then these maximum sizes would be need to be recalculated and + updated. */ +#define ENOUGH_LENS 852 +#define ENOUGH_DISTS 592 +#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) + +/* Type of code to build for inflate_table() */ +typedef enum { + CODES, + LENS, + DISTS +} codetype; + +int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, + unsigned codes, code FAR * FAR *table, + unsigned FAR *bits, unsigned short FAR *work)); diff --git a/test/zlib/zlib-1.2.8/make_vms.com b/test/zlib/zlib-1.2.8/make_vms.com new file mode 100644 index 000000000..65e9d0cbc --- /dev/null +++ b/test/zlib/zlib-1.2.8/make_vms.com @@ -0,0 +1,867 @@ +$! make libz under VMS written by +$! Martin P.J. Zinser +$! +$! In case of problems with the install you might contact me at +$! zinser@zinser.no-ip.info(preferred) or +$! martin.zinser@eurexchange.com (work) +$! +$! Make procedure history for Zlib +$! +$!------------------------------------------------------------------------------ +$! Version history +$! 0.01 20060120 First version to receive a number +$! 0.02 20061008 Adapt to new Makefile.in +$! 0.03 20091224 Add support for large file check +$! 0.04 20100110 Add new gzclose, gzlib, gzread, gzwrite +$! 0.05 20100221 Exchange zlibdefs.h by zconf.h.in +$! 0.06 20120111 Fix missing amiss_err, update zconf_h.in, fix new exmples +$! subdir path, update module search in makefile.in +$! 0.07 20120115 Triggered by work done by Alexey Chupahin completly redesigned +$! shared image creation +$! 0.08 20120219 Make it work on VAX again, pre-load missing symbols to shared +$! image +$! 0.09 20120305 SMS. P1 sets builder ("MMK", "MMS", " " (built-in)). +$! "" -> automatic, preference: MMK, MMS, built-in. +$! +$ on error then goto err_exit +$! +$ true = 1 +$ false = 0 +$ tmpnam = "temp_" + f$getjpi("","pid") +$ tt = tmpnam + ".txt" +$ tc = tmpnam + ".c" +$ th = tmpnam + ".h" +$ define/nolog tconfig 'th' +$ its_decc = false +$ its_vaxc = false +$ its_gnuc = false +$ s_case = False +$! +$! Setup variables holding "config" information +$! +$ Make = "''p1'" +$ name = "Zlib" +$ version = "?.?.?" +$ v_string = "ZLIB_VERSION" +$ v_file = "zlib.h" +$ ccopt = "/include = []" +$ lopts = "" +$ dnsrl = "" +$ aconf_in_file = "zconf.h.in#zconf.h_in#zconf_h.in" +$ conf_check_string = "" +$ linkonly = false +$ optfile = name + ".opt" +$ mapfile = name + ".map" +$ libdefs = "" +$ vax = f$getsyi("HW_MODEL").lt.1024 +$ axp = f$getsyi("HW_MODEL").ge.1024 .and. f$getsyi("HW_MODEL").lt.4096 +$ ia64 = f$getsyi("HW_MODEL").ge.4096 +$! +$! 2012-03-05 SMS. +$! Why is this needed? And if it is needed, why not simply ".not. vax"? +$! +$!!! if axp .or. ia64 then set proc/parse=extended +$! +$ whoami = f$parse(f$environment("Procedure"),,,,"NO_CONCEAL") +$ mydef = F$parse(whoami,,,"DEVICE") +$ mydir = f$parse(whoami,,,"DIRECTORY") - "][" +$ myproc = f$parse(whoami,,,"Name") + f$parse(whoami,,,"type") +$! +$! Check for MMK/MMS +$! +$ if (Make .eqs. "") +$ then +$ If F$Search ("Sys$System:MMS.EXE") .nes. "" Then Make = "MMS" +$ If F$Type (MMK) .eqs. "STRING" Then Make = "MMK" +$ else +$ Make = f$edit( Make, "trim") +$ endif +$! +$ gosub find_version +$! +$ open/write topt tmp.opt +$ open/write optf 'optfile' +$! +$ gosub check_opts +$! +$! Look for the compiler used +$! +$ gosub check_compiler +$ close topt +$ close optf +$! +$ if its_decc +$ then +$ ccopt = "/prefix=all" + ccopt +$ if f$trnlnm("SYS") .eqs. "" +$ then +$ if axp +$ then +$ define sys sys$library: +$ else +$ ccopt = "/decc" + ccopt +$ define sys decc$library_include: +$ endif +$ endif +$! +$! 2012-03-05 SMS. +$! Why /NAMES = AS_IS? Why not simply ".not. vax"? And why not on VAX? +$! +$ if axp .or. ia64 +$ then +$ ccopt = ccopt + "/name=as_is/opt=(inline=speed)" +$ s_case = true +$ endif +$ endif +$ if its_vaxc .or. its_gnuc +$ then +$ if f$trnlnm("SYS").eqs."" then define sys sys$library: +$ endif +$! +$! Build a fake configure input header +$! +$ open/write conf_hin config.hin +$ write conf_hin "#undef _LARGEFILE64_SOURCE" +$ close conf_hin +$! +$! +$ i = 0 +$FIND_ACONF: +$ fname = f$element(i,"#",aconf_in_file) +$ if fname .eqs. "#" then goto AMISS_ERR +$ if f$search(fname) .eqs. "" +$ then +$ i = i + 1 +$ goto find_aconf +$ endif +$ open/read/err=aconf_err aconf_in 'fname' +$ open/write aconf zconf.h +$ACONF_LOOP: +$ read/end_of_file=aconf_exit aconf_in line +$ work = f$edit(line, "compress,trim") +$ if f$extract(0,6,work) .nes. "#undef" +$ then +$ if f$extract(0,12,work) .nes. "#cmakedefine" +$ then +$ write aconf line +$ endif +$ else +$ cdef = f$element(1," ",work) +$ gosub check_config +$ endif +$ goto aconf_loop +$ACONF_EXIT: +$ write aconf "" +$ write aconf "/* VMS specifics added by make_vms.com: */" +$ write aconf "#define VMS 1" +$ write aconf "#include " +$ write aconf "#include " +$ write aconf "#ifdef _LARGEFILE" +$ write aconf "# define off64_t __off64_t" +$ write aconf "# define fopen64 fopen" +$ write aconf "# define fseeko64 fseeko" +$ write aconf "# define lseek64 lseek" +$ write aconf "# define ftello64 ftell" +$ write aconf "#endif" +$ write aconf "#if !defined( __VAX) && (__CRTL_VER >= 70312000)" +$ write aconf "# define HAVE_VSNPRINTF" +$ write aconf "#endif" +$ close aconf_in +$ close aconf +$ if f$search("''th'") .nes. "" then delete 'th';* +$! Build the thing plain or with mms +$! +$ write sys$output "Compiling Zlib sources ..." +$ if make.eqs."" +$ then +$ if (f$search( "example.obj;*") .nes. "") then delete example.obj;* +$ if (f$search( "minigzip.obj;*") .nes. "") then delete minigzip.obj;* +$ CALL MAKE adler32.OBJ "CC ''CCOPT' adler32" - + adler32.c zlib.h zconf.h +$ CALL MAKE compress.OBJ "CC ''CCOPT' compress" - + compress.c zlib.h zconf.h +$ CALL MAKE crc32.OBJ "CC ''CCOPT' crc32" - + crc32.c zlib.h zconf.h +$ CALL MAKE deflate.OBJ "CC ''CCOPT' deflate" - + deflate.c deflate.h zutil.h zlib.h zconf.h +$ CALL MAKE gzclose.OBJ "CC ''CCOPT' gzclose" - + gzclose.c zutil.h zlib.h zconf.h +$ CALL MAKE gzlib.OBJ "CC ''CCOPT' gzlib" - + gzlib.c zutil.h zlib.h zconf.h +$ CALL MAKE gzread.OBJ "CC ''CCOPT' gzread" - + gzread.c zutil.h zlib.h zconf.h +$ CALL MAKE gzwrite.OBJ "CC ''CCOPT' gzwrite" - + gzwrite.c zutil.h zlib.h zconf.h +$ CALL MAKE infback.OBJ "CC ''CCOPT' infback" - + infback.c zutil.h inftrees.h inflate.h inffast.h inffixed.h +$ CALL MAKE inffast.OBJ "CC ''CCOPT' inffast" - + inffast.c zutil.h zlib.h zconf.h inffast.h +$ CALL MAKE inflate.OBJ "CC ''CCOPT' inflate" - + inflate.c zutil.h zlib.h zconf.h infblock.h +$ CALL MAKE inftrees.OBJ "CC ''CCOPT' inftrees" - + inftrees.c zutil.h zlib.h zconf.h inftrees.h +$ CALL MAKE trees.OBJ "CC ''CCOPT' trees" - + trees.c deflate.h zutil.h zlib.h zconf.h +$ CALL MAKE uncompr.OBJ "CC ''CCOPT' uncompr" - + uncompr.c zlib.h zconf.h +$ CALL MAKE zutil.OBJ "CC ''CCOPT' zutil" - + zutil.c zutil.h zlib.h zconf.h +$ write sys$output "Building Zlib ..." +$ CALL MAKE libz.OLB "lib/crea libz.olb *.obj" *.OBJ +$ write sys$output "Building example..." +$ CALL MAKE example.OBJ "CC ''CCOPT' [.test]example" - + [.test]example.c zlib.h zconf.h +$ call make example.exe "LINK example,libz.olb/lib" example.obj libz.olb +$ write sys$output "Building minigzip..." +$ CALL MAKE minigzip.OBJ "CC ''CCOPT' [.test]minigzip" - + [.test]minigzip.c zlib.h zconf.h +$ call make minigzip.exe - + "LINK minigzip,libz.olb/lib" - + minigzip.obj libz.olb +$ else +$ gosub crea_mms +$ write sys$output "Make ''name' ''version' with ''Make' " +$ 'make' +$ endif +$! +$! Create shareable image +$! +$ gosub crea_olist +$ write sys$output "Creating libzshr.exe" +$ call map_2_shopt 'mapfile' 'optfile' +$ LINK_'lopts'/SHARE=libzshr.exe modules.opt/opt,'optfile'/opt +$ write sys$output "Zlib build completed" +$ delete/nolog tmp.opt;* +$ exit +$AMISS_ERR: +$ write sys$output "No source for config.hin found." +$ write sys$output "Tried any of ''aconf_in_file'" +$ goto err_exit +$CC_ERR: +$ write sys$output "C compiler required to build ''name'" +$ goto err_exit +$ERR_EXIT: +$ set message/facil/ident/sever/text +$ close/nolog optf +$ close/nolog topt +$ close/nolog aconf_in +$ close/nolog aconf +$ close/nolog out +$ close/nolog min +$ close/nolog mod +$ close/nolog h_in +$ write sys$output "Exiting..." +$ exit 2 +$! +$! +$MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES +$ V = 'F$Verify(0) +$! P1 = What we are trying to make +$! P2 = Command to make it +$! P3 - P8 What it depends on +$ +$ If F$Search(P1) .Eqs. "" Then Goto Makeit +$ Time = F$CvTime(F$File(P1,"RDT")) +$arg=3 +$Loop: +$ Argument = P'arg +$ If Argument .Eqs. "" Then Goto Exit +$ El=0 +$Loop2: +$ File = F$Element(El," ",Argument) +$ If File .Eqs. " " Then Goto Endl +$ AFile = "" +$Loop3: +$ OFile = AFile +$ AFile = F$Search(File) +$ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl +$ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit +$ Goto Loop3 +$NextEL: +$ El = El + 1 +$ Goto Loop2 +$EndL: +$ arg=arg+1 +$ If arg .Le. 8 Then Goto Loop +$ Goto Exit +$ +$Makeit: +$ VV=F$VERIFY(0) +$ write sys$output P2 +$ 'P2 +$ VV='F$Verify(VV) +$Exit: +$ If V Then Set Verify +$ENDSUBROUTINE +$!------------------------------------------------------------------------------ +$! +$! Check command line options and set symbols accordingly +$! +$!------------------------------------------------------------------------------ +$! Version history +$! 0.01 20041206 First version to receive a number +$! 0.02 20060126 Add new "HELP" target +$ CHECK_OPTS: +$ i = 1 +$ OPT_LOOP: +$ if i .lt. 9 +$ then +$ cparm = f$edit(p'i',"upcase") +$! +$! Check if parameter actually contains something +$! +$ if f$edit(cparm,"trim") .nes. "" +$ then +$ if cparm .eqs. "DEBUG" +$ then +$ ccopt = ccopt + "/noopt/deb" +$ lopts = lopts + "/deb" +$ endif +$ if f$locate("CCOPT=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ ccopt = ccopt + f$extract(start,len,cparm) +$ if f$locate("AS_IS",f$edit(ccopt,"UPCASE")) .lt. f$length(ccopt) - + then s_case = true +$ endif +$ if cparm .eqs. "LINK" then linkonly = true +$ if f$locate("LOPTS=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ lopts = lopts + f$extract(start,len,cparm) +$ endif +$ if f$locate("CC=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ cc_com = f$extract(start,len,cparm) + if (cc_com .nes. "DECC") .and. - + (cc_com .nes. "VAXC") .and. - + (cc_com .nes. "GNUC") +$ then +$ write sys$output "Unsupported compiler choice ''cc_com' ignored" +$ write sys$output "Use DECC, VAXC, or GNUC instead" +$ else +$ if cc_com .eqs. "DECC" then its_decc = true +$ if cc_com .eqs. "VAXC" then its_vaxc = true +$ if cc_com .eqs. "GNUC" then its_gnuc = true +$ endif +$ endif +$ if f$locate("MAKE=",cparm) .lt. f$length(cparm) +$ then +$ start = f$locate("=",cparm) + 1 +$ len = f$length(cparm) - start +$ mmks = f$extract(start,len,cparm) +$ if (mmks .eqs. "MMK") .or. (mmks .eqs. "MMS") +$ then +$ make = mmks +$ else +$ write sys$output "Unsupported make choice ''mmks' ignored" +$ write sys$output "Use MMK or MMS instead" +$ endif +$ endif +$ if cparm .eqs. "HELP" then gosub bhelp +$ endif +$ i = i + 1 +$ goto opt_loop +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Look for the compiler used +$! +$! Version history +$! 0.01 20040223 First version to receive a number +$! 0.02 20040229 Save/set value of decc$no_rooted_search_lists +$! 0.03 20060202 Extend handling of GNU C +$! 0.04 20090402 Compaq -> hp +$CHECK_COMPILER: +$ if (.not. (its_decc .or. its_vaxc .or. its_gnuc)) +$ then +$ its_decc = (f$search("SYS$SYSTEM:DECC$COMPILER.EXE") .nes. "") +$ its_vaxc = .not. its_decc .and. (F$Search("SYS$System:VAXC.Exe") .nes. "") +$ its_gnuc = .not. (its_decc .or. its_vaxc) .and. (f$trnlnm("gnu_cc") .nes. "") +$ endif +$! +$! Exit if no compiler available +$! +$ if (.not. (its_decc .or. its_vaxc .or. its_gnuc)) +$ then goto CC_ERR +$ else +$ if its_decc +$ then +$ write sys$output "CC compiler check ... hp C" +$ if f$trnlnm("decc$no_rooted_search_lists") .nes. "" +$ then +$ dnrsl = f$trnlnm("decc$no_rooted_search_lists") +$ endif +$ define/nolog decc$no_rooted_search_lists 1 +$ else +$ if its_vaxc then write sys$output "CC compiler check ... VAX C" +$ if its_gnuc +$ then +$ write sys$output "CC compiler check ... GNU C" +$ if f$trnlnm(topt) then write topt "gnu_cc:[000000]gcclib.olb/lib" +$ if f$trnlnm(optf) then write optf "gnu_cc:[000000]gcclib.olb/lib" +$ cc = "gcc" +$ endif +$ if f$trnlnm(topt) then write topt "sys$share:vaxcrtl.exe/share" +$ if f$trnlnm(optf) then write optf "sys$share:vaxcrtl.exe/share" +$ endif +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! If MMS/MMK are available dump out the descrip.mms if required +$! +$CREA_MMS: +$ write sys$output "Creating descrip.mms..." +$ create descrip.mms +$ open/append out descrip.mms +$ copy sys$input: out +$ deck +# descrip.mms: MMS description file for building zlib on VMS +# written by Martin P.J. Zinser +# + +OBJS = adler32.obj, compress.obj, crc32.obj, gzclose.obj, gzlib.obj\ + gzread.obj, gzwrite.obj, uncompr.obj, infback.obj\ + deflate.obj, trees.obj, zutil.obj, inflate.obj, \ + inftrees.obj, inffast.obj + +$ eod +$ write out "CFLAGS=", ccopt +$ write out "LOPTS=", lopts +$ write out "all : example.exe minigzip.exe libz.olb" +$ copy sys$input: out +$ deck + @ write sys$output " Example applications available" + +libz.olb : libz.olb($(OBJS)) + @ write sys$output " libz available" + +example.exe : example.obj libz.olb + link $(LOPTS) example,libz.olb/lib + +minigzip.exe : minigzip.obj libz.olb + link $(LOPTS) minigzip,libz.olb/lib + +clean : + delete *.obj;*,libz.olb;*,*.opt;*,*.exe;* + + +# Other dependencies. +adler32.obj : adler32.c zutil.h zlib.h zconf.h +compress.obj : compress.c zlib.h zconf.h +crc32.obj : crc32.c zutil.h zlib.h zconf.h +deflate.obj : deflate.c deflate.h zutil.h zlib.h zconf.h +example.obj : [.test]example.c zlib.h zconf.h +gzclose.obj : gzclose.c zutil.h zlib.h zconf.h +gzlib.obj : gzlib.c zutil.h zlib.h zconf.h +gzread.obj : gzread.c zutil.h zlib.h zconf.h +gzwrite.obj : gzwrite.c zutil.h zlib.h zconf.h +inffast.obj : inffast.c zutil.h zlib.h zconf.h inftrees.h inffast.h +inflate.obj : inflate.c zutil.h zlib.h zconf.h +inftrees.obj : inftrees.c zutil.h zlib.h zconf.h inftrees.h +minigzip.obj : [.test]minigzip.c zlib.h zconf.h +trees.obj : trees.c deflate.h zutil.h zlib.h zconf.h +uncompr.obj : uncompr.c zlib.h zconf.h +zutil.obj : zutil.c zutil.h zlib.h zconf.h +infback.obj : infback.c zutil.h inftrees.h inflate.h inffast.h inffixed.h +$ eod +$ close out +$ return +$!------------------------------------------------------------------------------ +$! +$! Read list of core library sources from makefile.in and create options +$! needed to build shareable image +$! +$CREA_OLIST: +$ open/read min makefile.in +$ open/write mod modules.opt +$ src_check_list = "OBJZ =#OBJG =" +$MRLOOP: +$ read/end=mrdone min rec +$ i = 0 +$SRC_CHECK_LOOP: +$ src_check = f$element(i, "#", src_check_list) +$ i = i+1 +$ if src_check .eqs. "#" then goto mrloop +$ if (f$extract(0,6,rec) .nes. src_check) then goto src_check_loop +$ rec = rec - src_check +$ gosub extra_filnam +$ if (f$element(1,"\",rec) .eqs. "\") then goto mrloop +$MRSLOOP: +$ read/end=mrdone min rec +$ gosub extra_filnam +$ if (f$element(1,"\",rec) .nes. "\") then goto mrsloop +$MRDONE: +$ close min +$ close mod +$ return +$!------------------------------------------------------------------------------ +$! +$! Take record extracted in crea_olist and split it into single filenames +$! +$EXTRA_FILNAM: +$ myrec = f$edit(rec - "\", "trim,compress") +$ i = 0 +$FELOOP: +$ srcfil = f$element(i," ", myrec) +$ if (srcfil .nes. " ") +$ then +$ write mod f$parse(srcfil,,,"NAME"), ".obj" +$ i = i + 1 +$ goto feloop +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Find current Zlib version number +$! +$FIND_VERSION: +$ open/read h_in 'v_file' +$hloop: +$ read/end=hdone h_in rec +$ rec = f$edit(rec,"TRIM") +$ if (f$extract(0,1,rec) .nes. "#") then goto hloop +$ rec = f$edit(rec - "#", "TRIM") +$ if f$element(0," ",rec) .nes. "define" then goto hloop +$ if f$element(1," ",rec) .eqs. v_string +$ then +$ version = 'f$element(2," ",rec)' +$ goto hdone +$ endif +$ goto hloop +$hdone: +$ close h_in +$ return +$!------------------------------------------------------------------------------ +$! +$CHECK_CONFIG: +$! +$ in_ldef = f$locate(cdef,libdefs) +$ if (in_ldef .lt. f$length(libdefs)) +$ then +$ write aconf "#define ''cdef' 1" +$ libdefs = f$extract(0,in_ldef,libdefs) + - + f$extract(in_ldef + f$length(cdef) + 1, - + f$length(libdefs) - in_ldef - f$length(cdef) - 1, - + libdefs) +$ else +$ if (f$type('cdef') .eqs. "INTEGER") +$ then +$ write aconf "#define ''cdef' ", 'cdef' +$ else +$ if (f$type('cdef') .eqs. "STRING") +$ then +$ write aconf "#define ''cdef' ", """", '''cdef'', """" +$ else +$ gosub check_cc_def +$ endif +$ endif +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Check if this is a define relating to the properties of the C/C++ +$! compiler +$! +$ CHECK_CC_DEF: +$ if (cdef .eqs. "_LARGEFILE64_SOURCE") +$ then +$ copy sys$input: 'tc' +$ deck +#include "tconfig" +#define _LARGEFILE +#include + +int main(){ +FILE *fp; + fp = fopen("temp.txt","r"); + fseeko(fp,1,SEEK_SET); + fclose(fp); +} + +$ eod +$ test_inv = false +$ comm_h = false +$ gosub cc_prop_check +$ return +$ endif +$ write aconf "/* ", line, " */" +$ return +$!------------------------------------------------------------------------------ +$! +$! Check for properties of C/C++ compiler +$! +$! Version history +$! 0.01 20031020 First version to receive a number +$! 0.02 20031022 Added logic for defines with value +$! 0.03 20040309 Make sure local config file gets not deleted +$! 0.04 20041230 Also write include for configure run +$! 0.05 20050103 Add processing of "comment defines" +$CC_PROP_CHECK: +$ cc_prop = true +$ is_need = false +$ is_need = (f$extract(0,4,cdef) .eqs. "NEED") .or. (test_inv .eq. true) +$ if f$search(th) .eqs. "" then create 'th' +$ set message/nofac/noident/nosever/notext +$ on error then continue +$ cc 'tmpnam' +$ if .not. ($status) then cc_prop = false +$ on error then continue +$! The headers might lie about the capabilities of the RTL +$ link 'tmpnam',tmp.opt/opt +$ if .not. ($status) then cc_prop = false +$ set message/fac/ident/sever/text +$ on error then goto err_exit +$ delete/nolog 'tmpnam'.*;*/exclude='th' +$ if (cc_prop .and. .not. is_need) .or. - + (.not. cc_prop .and. is_need) +$ then +$ write sys$output "Checking for ''cdef'... yes" +$ if f$type('cdef_val'_yes) .nes. "" +$ then +$ if f$type('cdef_val'_yes) .eqs. "INTEGER" - + then call write_config f$fao("#define !AS !UL",cdef,'cdef_val'_yes) +$ if f$type('cdef_val'_yes) .eqs. "STRING" - + then call write_config f$fao("#define !AS !AS",cdef,'cdef_val'_yes) +$ else +$ call write_config f$fao("#define !AS 1",cdef) +$ endif +$ if (cdef .eqs. "HAVE_FSEEKO") .or. (cdef .eqs. "_LARGE_FILES") .or. - + (cdef .eqs. "_LARGEFILE64_SOURCE") then - + call write_config f$string("#define _LARGEFILE 1") +$ else +$ write sys$output "Checking for ''cdef'... no" +$ if (comm_h) +$ then + call write_config f$fao("/* !AS */",line) +$ else +$ if f$type('cdef_val'_no) .nes. "" +$ then +$ if f$type('cdef_val'_no) .eqs. "INTEGER" - + then call write_config f$fao("#define !AS !UL",cdef,'cdef_val'_no) +$ if f$type('cdef_val'_no) .eqs. "STRING" - + then call write_config f$fao("#define !AS !AS",cdef,'cdef_val'_no) +$ else +$ call write_config f$fao("#undef !AS",cdef) +$ endif +$ endif +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Check for properties of C/C++ compiler with multiple result values +$! +$! Version history +$! 0.01 20040127 First version +$! 0.02 20050103 Reconcile changes from cc_prop up to version 0.05 +$CC_MPROP_CHECK: +$ cc_prop = true +$ i = 1 +$ idel = 1 +$ MT_LOOP: +$ if f$type(result_'i') .eqs. "STRING" +$ then +$ set message/nofac/noident/nosever/notext +$ on error then continue +$ cc 'tmpnam'_'i' +$ if .not. ($status) then cc_prop = false +$ on error then continue +$! The headers might lie about the capabilities of the RTL +$ link 'tmpnam'_'i',tmp.opt/opt +$ if .not. ($status) then cc_prop = false +$ set message/fac/ident/sever/text +$ on error then goto err_exit +$ delete/nolog 'tmpnam'_'i'.*;* +$ if (cc_prop) +$ then +$ write sys$output "Checking for ''cdef'... ", mdef_'i' +$ if f$type(mdef_'i') .eqs. "INTEGER" - + then call write_config f$fao("#define !AS !UL",cdef,mdef_'i') +$ if f$type('cdef_val'_yes) .eqs. "STRING" - + then call write_config f$fao("#define !AS !AS",cdef,mdef_'i') +$ goto msym_clean +$ else +$ i = i + 1 +$ goto mt_loop +$ endif +$ endif +$ write sys$output "Checking for ''cdef'... no" +$ call write_config f$fao("#undef !AS",cdef) +$ MSYM_CLEAN: +$ if (idel .le. msym_max) +$ then +$ delete/sym mdef_'idel' +$ idel = idel + 1 +$ goto msym_clean +$ endif +$ return +$!------------------------------------------------------------------------------ +$! +$! Write configuration to both permanent and temporary config file +$! +$! Version history +$! 0.01 20031029 First version to receive a number +$! +$WRITE_CONFIG: SUBROUTINE +$ write aconf 'p1' +$ open/append confh 'th' +$ write confh 'p1' +$ close confh +$ENDSUBROUTINE +$!------------------------------------------------------------------------------ +$! +$! Analyze the project map file and create the symbol vector for a shareable +$! image from it +$! +$! Version history +$! 0.01 20120128 First version +$! 0.02 20120226 Add pre-load logic +$! +$ MAP_2_SHOPT: Subroutine +$! +$ SAY := "WRITE_ SYS$OUTPUT" +$! +$ IF F$SEARCH("''P1'") .EQS. "" +$ THEN +$ SAY "MAP_2_SHOPT-E-NOSUCHFILE: Error, inputfile ''p1' not available" +$ goto exit_m2s +$ ENDIF +$ IF "''P2'" .EQS. "" +$ THEN +$ SAY "MAP_2_SHOPT: Error, no output file provided" +$ goto exit_m2s +$ ENDIF +$! +$ module1 = "deflate#deflateEnd#deflateInit_#deflateParams#deflateSetDictionary" +$ module2 = "gzclose#gzerror#gzgetc#gzgets#gzopen#gzprintf#gzputc#gzputs#gzread" +$ module3 = "gzseek#gztell#inflate#inflateEnd#inflateInit_#inflateSetDictionary" +$ module4 = "inflateSync#uncompress#zlibVersion#compress" +$ open/read map 'p1 +$ if axp .or. ia64 +$ then +$ open/write aopt a.opt +$ open/write bopt b.opt +$ write aopt " CASE_SENSITIVE=YES" +$ write bopt "SYMBOL_VECTOR= (-" +$ mod_sym_num = 1 +$ MOD_SYM_LOOP: +$ if f$type(module'mod_sym_num') .nes. "" +$ then +$ mod_in = 0 +$ MOD_SYM_IN: +$ shared_proc = f$element(mod_in, "#", module'mod_sym_num') +$ if shared_proc .nes. "#" +$ then +$ write aopt f$fao(" symbol_vector=(!AS/!AS=PROCEDURE)",- + f$edit(shared_proc,"upcase"),shared_proc) +$ write bopt f$fao("!AS=PROCEDURE,-",shared_proc) +$ mod_in = mod_in + 1 +$ goto mod_sym_in +$ endif +$ mod_sym_num = mod_sym_num + 1 +$ goto mod_sym_loop +$ endif +$MAP_LOOP: +$ read/end=map_end map line +$ if (f$locate("{",line).lt. f$length(line)) .or. - + (f$locate("global:", line) .lt. f$length(line)) +$ then +$ proc = true +$ goto map_loop +$ endif +$ if f$locate("}",line).lt. f$length(line) then proc = false +$ if f$locate("local:", line) .lt. f$length(line) then proc = false +$ if proc +$ then +$ shared_proc = f$edit(line,"collapse") +$ chop_semi = f$locate(";", shared_proc) +$ if chop_semi .lt. f$length(shared_proc) then - + shared_proc = f$extract(0, chop_semi, shared_proc) +$ write aopt f$fao(" symbol_vector=(!AS/!AS=PROCEDURE)",- + f$edit(shared_proc,"upcase"),shared_proc) +$ write bopt f$fao("!AS=PROCEDURE,-",shared_proc) +$ endif +$ goto map_loop +$MAP_END: +$ close/nolog aopt +$ close/nolog bopt +$ open/append libopt 'p2' +$ open/read aopt a.opt +$ open/read bopt b.opt +$ALOOP: +$ read/end=aloop_end aopt line +$ write libopt line +$ goto aloop +$ALOOP_END: +$ close/nolog aopt +$ sv = "" +$BLOOP: +$ read/end=bloop_end bopt svn +$ if (svn.nes."") +$ then +$ if (sv.nes."") then write libopt sv +$ sv = svn +$ endif +$ goto bloop +$BLOOP_END: +$ write libopt f$extract(0,f$length(sv)-2,sv), "-" +$ write libopt ")" +$ close/nolog bopt +$ delete/nolog/noconf a.opt;*,b.opt;* +$ else +$ if vax +$ then +$ open/append libopt 'p2' +$ mod_sym_num = 1 +$ VMOD_SYM_LOOP: +$ if f$type(module'mod_sym_num') .nes. "" +$ then +$ mod_in = 0 +$ VMOD_SYM_IN: +$ shared_proc = f$element(mod_in, "#", module'mod_sym_num') +$ if shared_proc .nes. "#" +$ then +$ write libopt f$fao("UNIVERSAL=!AS",- + f$edit(shared_proc,"upcase")) +$ mod_in = mod_in + 1 +$ goto vmod_sym_in +$ endif +$ mod_sym_num = mod_sym_num + 1 +$ goto vmod_sym_loop +$ endif +$VMAP_LOOP: +$ read/end=vmap_end map line +$ if (f$locate("{",line).lt. f$length(line)) .or. - + (f$locate("global:", line) .lt. f$length(line)) +$ then +$ proc = true +$ goto vmap_loop +$ endif +$ if f$locate("}",line).lt. f$length(line) then proc = false +$ if f$locate("local:", line) .lt. f$length(line) then proc = false +$ if proc +$ then +$ shared_proc = f$edit(line,"collapse") +$ chop_semi = f$locate(";", shared_proc) +$ if chop_semi .lt. f$length(shared_proc) then - + shared_proc = f$extract(0, chop_semi, shared_proc) +$ write libopt f$fao("UNIVERSAL=!AS",- + f$edit(shared_proc,"upcase")) +$ endif +$ goto vmap_loop +$VMAP_END: +$ else +$ write sys$output "Unknown Architecture (Not VAX, AXP, or IA64)" +$ write sys$output "No options file created" +$ endif +$ endif +$ EXIT_M2S: +$ close/nolog map +$ close/nolog libopt +$ endsubroutine diff --git a/test/zlib/zlib-1.2.8/msdos/Makefile.bor b/test/zlib/zlib-1.2.8/msdos/Makefile.bor new file mode 100644 index 000000000..3d12a2c25 --- /dev/null +++ b/test/zlib/zlib-1.2.8/msdos/Makefile.bor @@ -0,0 +1,115 @@ +# Makefile for zlib +# Borland C++ +# Last updated: 15-Mar-2003 + +# To use, do "make -fmakefile.bor" +# To compile in small model, set below: MODEL=s + +# WARNING: the small model is supported but only for small values of +# MAX_WBITS and MAX_MEM_LEVEL. For example: +# -DMAX_WBITS=11 -DDEF_WBITS=11 -DMAX_MEM_LEVEL=3 +# If you wish to reduce the memory requirements (default 256K for big +# objects plus a few K), you can add to the LOC macro below: +# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14 +# See zconf.h for details about the memory requirements. + +# ------------ Turbo C++, Borland C++ ------------ + +# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7) +# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or added +# to the declaration of LOC here: +LOC = $(LOCAL_ZLIB) + +# type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc. +CPU_TYP = 0 + +# memory model: one of s, m, c, l (small, medium, compact, large) +MODEL=l + +# replace bcc with tcc for Turbo C++ 1.0, with bcc32 for the 32 bit version +CC=bcc +LD=bcc +AR=tlib + +# compiler flags +# replace "-O2" by "-O -G -a -d" for Turbo C++ 1.0 +CFLAGS=-O2 -Z -m$(MODEL) $(LOC) + +LDFLAGS=-m$(MODEL) -f- + + +# variables +ZLIB_LIB = zlib_$(MODEL).lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj +OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: test/example.c zlib.h zconf.h + +minigzip.obj: test/minigzip.c zlib.h zconf.h + + +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +clean: + -del *.obj + -del *.lib + -del *.exe + -del zlib_*.bak + -del foo.gz diff --git a/test/zlib/zlib-1.2.8/msdos/Makefile.dj2 b/test/zlib/zlib-1.2.8/msdos/Makefile.dj2 new file mode 100644 index 000000000..29b03954d --- /dev/null +++ b/test/zlib/zlib-1.2.8/msdos/Makefile.dj2 @@ -0,0 +1,104 @@ +# Makefile for zlib. Modified for djgpp v2.0 by F. J. Donahoe, 3/15/96. +# Copyright (C) 1995-1998 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type: +# +# make -fmakefile.dj2; make test -fmakefile.dj2 +# +# To install libz.a, zconf.h and zlib.h in the djgpp directories, type: +# +# make install -fmakefile.dj2 +# +# after first defining LIBRARY_PATH and INCLUDE_PATH in djgpp.env as +# in the sample below if the pattern of the DJGPP distribution is to +# be followed. Remember that, while 'es around <=> are ignored in +# makefiles, they are *not* in batch files or in djgpp.env. +# - - - - - +# [make] +# INCLUDE_PATH=%\>;INCLUDE_PATH%%\DJDIR%\include +# LIBRARY_PATH=%\>;LIBRARY_PATH%%\DJDIR%\lib +# BUTT=-m486 +# - - - - - +# Alternately, these variables may be defined below, overriding the values +# in djgpp.env, as +# INCLUDE_PATH=c:\usr\include +# LIBRARY_PATH=c:\usr\lib + +CC=gcc + +#CFLAGS=-MMD -O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-MMD -g -DDEBUG +CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ + -Wstrict-prototypes -Wmissing-prototypes + +# If cp.exe is available, replace "copy /Y" with "cp -fp" . +CP=copy /Y +# If gnu install.exe is available, replace $(CP) with ginstall. +INSTALL=$(CP) +# The default value of RM is "rm -f." If "rm.exe" is found, comment out: +RM=del +LDLIBS=-L. -lz +LD=$(CC) -s -o +LDSHARED=$(CC) + +INCL=zlib.h zconf.h +LIBS=libz.a + +AR=ar rcs + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \ + uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o + +OBJA = +# to use the asm code: make OBJA=match.o + +TEST_OBJS = example.o minigzip.o + +all: example.exe minigzip.exe + +check: test +test: all + ./example + echo hello world | .\minigzip | .\minigzip -d + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +libz.a: $(OBJS) $(OBJA) + $(AR) $@ $(OBJS) $(OBJA) + +%.exe : %.o $(LIBS) + $(LD) $@ $< $(LDLIBS) + +# INCLUDE_PATH and LIBRARY_PATH were set for [make] in djgpp.env . + +.PHONY : uninstall clean + +install: $(INCL) $(LIBS) + -@if not exist $(INCLUDE_PATH)\nul mkdir $(INCLUDE_PATH) + -@if not exist $(LIBRARY_PATH)\nul mkdir $(LIBRARY_PATH) + $(INSTALL) zlib.h $(INCLUDE_PATH) + $(INSTALL) zconf.h $(INCLUDE_PATH) + $(INSTALL) libz.a $(LIBRARY_PATH) + +uninstall: + $(RM) $(INCLUDE_PATH)\zlib.h + $(RM) $(INCLUDE_PATH)\zconf.h + $(RM) $(LIBRARY_PATH)\libz.a + +clean: + $(RM) *.d + $(RM) *.o + $(RM) *.exe + $(RM) libz.a + $(RM) foo.gz + +DEPS := $(wildcard *.d) +ifneq ($(DEPS),) +include $(DEPS) +endif diff --git a/test/zlib/zlib-1.2.8/msdos/Makefile.emx b/test/zlib/zlib-1.2.8/msdos/Makefile.emx new file mode 100644 index 000000000..9c1b57a58 --- /dev/null +++ b/test/zlib/zlib-1.2.8/msdos/Makefile.emx @@ -0,0 +1,69 @@ +# Makefile for zlib. Modified for emx 0.9c by Chr. Spieler, 6/17/98. +# Copyright (C) 1995-1998 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type: +# +# make -fmakefile.emx; make test -fmakefile.emx +# + +CC=gcc + +#CFLAGS=-MMD -O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-MMD -g -DDEBUG +CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ + -Wstrict-prototypes -Wmissing-prototypes + +# If cp.exe is available, replace "copy /Y" with "cp -fp" . +CP=copy /Y +# If gnu install.exe is available, replace $(CP) with ginstall. +INSTALL=$(CP) +# The default value of RM is "rm -f." If "rm.exe" is found, comment out: +RM=del +LDLIBS=-L. -lzlib +LD=$(CC) -s -o +LDSHARED=$(CC) + +INCL=zlib.h zconf.h +LIBS=zlib.a + +AR=ar rcs + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \ + uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o + +TEST_OBJS = example.o minigzip.o + +all: example.exe minigzip.exe + +test: all + ./example + echo hello world | .\minigzip | .\minigzip -d + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +zlib.a: $(OBJS) + $(AR) $@ $(OBJS) + +%.exe : %.o $(LIBS) + $(LD) $@ $< $(LDLIBS) + + +.PHONY : clean + +clean: + $(RM) *.d + $(RM) *.o + $(RM) *.exe + $(RM) zlib.a + $(RM) foo.gz + +DEPS := $(wildcard *.d) +ifneq ($(DEPS),) +include $(DEPS) +endif diff --git a/test/zlib/zlib-1.2.8/msdos/Makefile.msc b/test/zlib/zlib-1.2.8/msdos/Makefile.msc new file mode 100644 index 000000000..ae8378615 --- /dev/null +++ b/test/zlib/zlib-1.2.8/msdos/Makefile.msc @@ -0,0 +1,112 @@ +# Makefile for zlib +# Microsoft C 5.1 or later +# Last updated: 19-Mar-2003 + +# To use, do "make makefile.msc" +# To compile in small model, set below: MODEL=S + +# If you wish to reduce the memory requirements (default 256K for big +# objects plus a few K), you can add to the LOC macro below: +# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14 +# See zconf.h for details about the memory requirements. + +# ------------- Microsoft C 5.1 and later ------------- + +# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7) +# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or added +# to the declaration of LOC here: +LOC = $(LOCAL_ZLIB) + +# Type for CPU required: 0: 8086, 1: 80186, 2: 80286, 3: 80386, etc. +CPU_TYP = 0 + +# Memory model: one of S, M, C, L (small, medium, compact, large) +MODEL=L + +CC=cl +CFLAGS=-nologo -A$(MODEL) -G$(CPU_TYP) -W3 -Oait -Gs $(LOC) +#-Ox generates bad code with MSC 5.1 +LIB_CFLAGS=-Zl $(CFLAGS) + +LD=link +LDFLAGS=/noi/e/st:0x1500/noe/farcall/packcode +# "/farcall/packcode" are only useful for `large code' memory models +# but should be a "no-op" for small code models. + + +# variables +ZLIB_LIB = zlib_$(MODEL).lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(LIB_CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: test/example.c zlib.h zconf.h + $(CC) -c $(CFLAGS) $*.c + +minigzip.obj: test/minigzip.c zlib.h zconf.h + $(CC) -c $(CFLAGS) $*.c + + +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + if exist $(ZLIB_LIB) del $(ZLIB_LIB) + lib $(ZLIB_LIB) $(OBJ1); + lib $(ZLIB_LIB) $(OBJ2); + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj,,,$(ZLIB_LIB); + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj,,,$(ZLIB_LIB); + +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +clean: + -del *.obj + -del *.lib + -del *.exe + -del *.map + -del zlib_*.bak + -del foo.gz diff --git a/test/zlib/zlib-1.2.8/msdos/Makefile.tc b/test/zlib/zlib-1.2.8/msdos/Makefile.tc new file mode 100644 index 000000000..5aec82a9d --- /dev/null +++ b/test/zlib/zlib-1.2.8/msdos/Makefile.tc @@ -0,0 +1,100 @@ +# Makefile for zlib +# Turbo C 2.01, Turbo C++ 1.01 +# Last updated: 15-Mar-2003 + +# To use, do "make -fmakefile.tc" +# To compile in small model, set below: MODEL=s + +# WARNING: the small model is supported but only for small values of +# MAX_WBITS and MAX_MEM_LEVEL. For example: +# -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3 +# If you wish to reduce the memory requirements (default 256K for big +# objects plus a few K), you can add to CFLAGS below: +# -DMAX_MEM_LEVEL=7 -DMAX_WBITS=14 +# See zconf.h for details about the memory requirements. + +# ------------ Turbo C 2.01, Turbo C++ 1.01 ------------ +MODEL=l +CC=tcc +LD=tcc +AR=tlib +# CFLAGS=-O2 -G -Z -m$(MODEL) -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3 +CFLAGS=-O2 -G -Z -m$(MODEL) +LDFLAGS=-m$(MODEL) -f- + + +# variables +ZLIB_LIB = zlib_$(MODEL).lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj +OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $*.c + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: test/example.c zlib.h zconf.h + +minigzip.obj: test/minigzip.c zlib.h zconf.h + + +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +clean: + -del *.obj + -del *.lib + -del *.exe + -del zlib_*.bak + -del foo.gz diff --git a/test/zlib/zlib-1.2.8/nintendods/Makefile b/test/zlib/zlib-1.2.8/nintendods/Makefile new file mode 100644 index 000000000..21337d01a --- /dev/null +++ b/test/zlib/zlib-1.2.8/nintendods/Makefile @@ -0,0 +1,126 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/ds_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# DATA is a list of directories containing data files +# INCLUDES is a list of directories containing header files +#--------------------------------------------------------------------------------- +TARGET := $(shell basename $(CURDIR)) +BUILD := build +SOURCES := ../../ +DATA := data +INCLUDES := include + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -mthumb -mthumb-interwork + +CFLAGS := -Wall -O2\ + -march=armv5te -mtune=arm946e-s \ + -fomit-frame-pointer -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM9 +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions + +ASFLAGS := $(ARCH) -march=armv5te -mtune=arm946e-s +LDFLAGS = -specs=ds_arm9.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(LIBNDS) + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/lib/libz.a + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + @[ -d $@ ] || mkdir -p include + @cp ../../*.h include + +lib: + @[ -d $@ ] || mkdir -p $@ + +$(BUILD): lib + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) lib + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT) : $(OFILES) + +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/test/zlib/zlib-1.2.8/nintendods/README b/test/zlib/zlib-1.2.8/nintendods/README new file mode 100644 index 000000000..ba7a37dbe --- /dev/null +++ b/test/zlib/zlib-1.2.8/nintendods/README @@ -0,0 +1,5 @@ +This Makefile requires devkitARM (http://www.devkitpro.org/category/devkitarm/) and works inside "contrib/nds". It is based on a devkitARM template. + +Eduardo Costa +January 3, 2009 + diff --git a/test/zlib/zlib-1.2.8/old/Makefile.emx b/test/zlib/zlib-1.2.8/old/Makefile.emx new file mode 100644 index 000000000..4d6ab0efa --- /dev/null +++ b/test/zlib/zlib-1.2.8/old/Makefile.emx @@ -0,0 +1,69 @@ +# Makefile for zlib. Modified for emx/rsxnt by Chr. Spieler, 6/16/98. +# Copyright (C) 1995-1998 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type: +# +# make -fmakefile.emx; make test -fmakefile.emx +# + +CC=gcc -Zwin32 + +#CFLAGS=-MMD -O +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-MMD -g -DDEBUG +CFLAGS=-MMD -O3 $(BUTT) -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ + -Wstrict-prototypes -Wmissing-prototypes + +# If cp.exe is available, replace "copy /Y" with "cp -fp" . +CP=copy /Y +# If gnu install.exe is available, replace $(CP) with ginstall. +INSTALL=$(CP) +# The default value of RM is "rm -f." If "rm.exe" is found, comment out: +RM=del +LDLIBS=-L. -lzlib +LD=$(CC) -s -o +LDSHARED=$(CC) + +INCL=zlib.h zconf.h +LIBS=zlib.a + +AR=ar rcs + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o deflate.o gzclose.o gzlib.o gzread.o \ + gzwrite.o infback.o inffast.o inflate.o inftrees.o trees.o uncompr.o zutil.o + +TEST_OBJS = example.o minigzip.o + +all: example.exe minigzip.exe + +test: all + ./example + echo hello world | .\minigzip | .\minigzip -d + +%.o : %.c + $(CC) $(CFLAGS) -c $< -o $@ + +zlib.a: $(OBJS) + $(AR) $@ $(OBJS) + +%.exe : %.o $(LIBS) + $(LD) $@ $< $(LDLIBS) + + +.PHONY : clean + +clean: + $(RM) *.d + $(RM) *.o + $(RM) *.exe + $(RM) zlib.a + $(RM) foo.gz + +DEPS := $(wildcard *.d) +ifneq ($(DEPS),) +include $(DEPS) +endif diff --git a/test/zlib/zlib-1.2.8/old/Makefile.riscos b/test/zlib/zlib-1.2.8/old/Makefile.riscos new file mode 100644 index 000000000..57e29d3fb --- /dev/null +++ b/test/zlib/zlib-1.2.8/old/Makefile.riscos @@ -0,0 +1,151 @@ +# Project: zlib_1_03 +# Patched for zlib 1.1.2 rw@shadow.org.uk 19980430 +# test works out-of-the-box, installs `somewhere' on demand + +# Toolflags: +CCflags = -c -depend !Depend -IC: -g -throwback -DRISCOS -fah +C++flags = -c -depend !Depend -IC: -throwback +Linkflags = -aif -c++ -o $@ +ObjAsmflags = -throwback -NoCache -depend !Depend +CMHGflags = +LibFileflags = -c -l -o $@ +Squeezeflags = -o $@ + +# change the line below to where _you_ want the library installed. +libdest = lib:zlib + +# Final targets: +@.lib: @.o.adler32 @.o.compress @.o.crc32 @.o.deflate @.o.gzio \ + @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil @.o.trees \ + @.o.uncompr @.o.zutil + LibFile $(LibFileflags) @.o.adler32 @.o.compress @.o.crc32 @.o.deflate \ + @.o.gzio @.o.infblock @.o.infcodes @.o.inffast @.o.inflate @.o.inftrees @.o.infutil \ + @.o.trees @.o.uncompr @.o.zutil +test: @.minigzip @.example @.lib + @copy @.lib @.libc A~C~DF~L~N~P~Q~RS~TV + @echo running tests: hang on. + @/@.minigzip -f -9 libc + @/@.minigzip -d libc-gz + @/@.minigzip -f -1 libc + @/@.minigzip -d libc-gz + @/@.minigzip -h -9 libc + @/@.minigzip -d libc-gz + @/@.minigzip -h -1 libc + @/@.minigzip -d libc-gz + @/@.minigzip -9 libc + @/@.minigzip -d libc-gz + @/@.minigzip -1 libc + @/@.minigzip -d libc-gz + @diff @.lib @.libc + @echo that should have reported '@.lib and @.libc identical' if you have diff. + @/@.example @.fred @.fred + @echo that will have given lots of hello!'s. + +@.minigzip: @.o.minigzip @.lib C:o.Stubs + Link $(Linkflags) @.o.minigzip @.lib C:o.Stubs +@.example: @.o.example @.lib C:o.Stubs + Link $(Linkflags) @.o.example @.lib C:o.Stubs + +install: @.lib + cdir $(libdest) + cdir $(libdest).h + @copy @.h.zlib $(libdest).h.zlib A~C~DF~L~N~P~Q~RS~TV + @copy @.h.zconf $(libdest).h.zconf A~C~DF~L~N~P~Q~RS~TV + @copy @.lib $(libdest).lib A~C~DF~L~N~P~Q~RS~TV + @echo okay, installed zlib in $(libdest) + +clean:; remove @.minigzip + remove @.example + remove @.libc + -wipe @.o.* F~r~cV + remove @.fred + +# User-editable dependencies: +.c.o: + cc $(ccflags) -o $@ $< + +# Static dependencies: + +# Dynamic dependencies: +o.example: c.example +o.example: h.zlib +o.example: h.zconf +o.minigzip: c.minigzip +o.minigzip: h.zlib +o.minigzip: h.zconf +o.adler32: c.adler32 +o.adler32: h.zlib +o.adler32: h.zconf +o.compress: c.compress +o.compress: h.zlib +o.compress: h.zconf +o.crc32: c.crc32 +o.crc32: h.zlib +o.crc32: h.zconf +o.deflate: c.deflate +o.deflate: h.deflate +o.deflate: h.zutil +o.deflate: h.zlib +o.deflate: h.zconf +o.gzio: c.gzio +o.gzio: h.zutil +o.gzio: h.zlib +o.gzio: h.zconf +o.infblock: c.infblock +o.infblock: h.zutil +o.infblock: h.zlib +o.infblock: h.zconf +o.infblock: h.infblock +o.infblock: h.inftrees +o.infblock: h.infcodes +o.infblock: h.infutil +o.infcodes: c.infcodes +o.infcodes: h.zutil +o.infcodes: h.zlib +o.infcodes: h.zconf +o.infcodes: h.inftrees +o.infcodes: h.infblock +o.infcodes: h.infcodes +o.infcodes: h.infutil +o.infcodes: h.inffast +o.inffast: c.inffast +o.inffast: h.zutil +o.inffast: h.zlib +o.inffast: h.zconf +o.inffast: h.inftrees +o.inffast: h.infblock +o.inffast: h.infcodes +o.inffast: h.infutil +o.inffast: h.inffast +o.inflate: c.inflate +o.inflate: h.zutil +o.inflate: h.zlib +o.inflate: h.zconf +o.inflate: h.infblock +o.inftrees: c.inftrees +o.inftrees: h.zutil +o.inftrees: h.zlib +o.inftrees: h.zconf +o.inftrees: h.inftrees +o.inftrees: h.inffixed +o.infutil: c.infutil +o.infutil: h.zutil +o.infutil: h.zlib +o.infutil: h.zconf +o.infutil: h.infblock +o.infutil: h.inftrees +o.infutil: h.infcodes +o.infutil: h.infutil +o.trees: c.trees +o.trees: h.deflate +o.trees: h.zutil +o.trees: h.zlib +o.trees: h.zconf +o.trees: h.trees +o.uncompr: c.uncompr +o.uncompr: h.zlib +o.uncompr: h.zconf +o.zutil: c.zutil +o.zutil: h.zutil +o.zutil: h.zlib +o.zutil: h.zconf diff --git a/test/zlib/zlib-1.2.8/old/README b/test/zlib/zlib-1.2.8/old/README new file mode 100644 index 000000000..800bf0798 --- /dev/null +++ b/test/zlib/zlib-1.2.8/old/README @@ -0,0 +1,3 @@ +This directory contains files that have not been updated for zlib 1.2.x + +(Volunteers are encouraged to help clean this up. Thanks.) diff --git a/test/zlib/zlib-1.2.8/old/descrip.mms b/test/zlib/zlib-1.2.8/old/descrip.mms new file mode 100644 index 000000000..7066da5b5 --- /dev/null +++ b/test/zlib/zlib-1.2.8/old/descrip.mms @@ -0,0 +1,48 @@ +# descrip.mms: MMS description file for building zlib on VMS +# written by Martin P.J. Zinser + +cc_defs = +c_deb = + +.ifdef __DECC__ +pref = /prefix=all +.endif + +OBJS = adler32.obj, compress.obj, crc32.obj, gzio.obj, uncompr.obj,\ + deflate.obj, trees.obj, zutil.obj, inflate.obj, infblock.obj,\ + inftrees.obj, infcodes.obj, infutil.obj, inffast.obj + +CFLAGS= $(C_DEB) $(CC_DEFS) $(PREF) + +all : example.exe minigzip.exe + @ write sys$output " Example applications available" +libz.olb : libz.olb($(OBJS)) + @ write sys$output " libz available" + +example.exe : example.obj libz.olb + link example,libz.olb/lib + +minigzip.exe : minigzip.obj libz.olb + link minigzip,libz.olb/lib,x11vms:xvmsutils.olb/lib + +clean : + delete *.obj;*,libz.olb;* + + +# Other dependencies. +adler32.obj : zutil.h zlib.h zconf.h +compress.obj : zlib.h zconf.h +crc32.obj : zutil.h zlib.h zconf.h +deflate.obj : deflate.h zutil.h zlib.h zconf.h +example.obj : zlib.h zconf.h +gzio.obj : zutil.h zlib.h zconf.h +infblock.obj : zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h +infcodes.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h infcodes.h inffast.h +inffast.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h inffast.h +inflate.obj : zutil.h zlib.h zconf.h infblock.h +inftrees.obj : zutil.h zlib.h zconf.h inftrees.h +infutil.obj : zutil.h zlib.h zconf.h inftrees.h infutil.h +minigzip.obj : zlib.h zconf.h +trees.obj : deflate.h zutil.h zlib.h zconf.h +uncompr.obj : zlib.h zconf.h +zutil.obj : zutil.h zlib.h zconf.h diff --git a/test/zlib/zlib-1.2.8/old/os2/Makefile.os2 b/test/zlib/zlib-1.2.8/old/os2/Makefile.os2 new file mode 100644 index 000000000..a105aaa5b --- /dev/null +++ b/test/zlib/zlib-1.2.8/old/os2/Makefile.os2 @@ -0,0 +1,136 @@ +# Makefile for zlib under OS/2 using GCC (PGCC) +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile and test, type: +# cp Makefile.os2 .. +# cd .. +# make -f Makefile.os2 test + +# This makefile will build a static library z.lib, a shared library +# z.dll and a import library zdll.lib. You can use either z.lib or +# zdll.lib by specifying either -lz or -lzdll on gcc's command line + +CC=gcc -Zomf -s + +CFLAGS=-O6 -Wall +#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#CFLAGS=-g -DDEBUG +#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes + +#################### BUG WARNING: ##################### +## infcodes.c hits a bug in pgcc-1.0, so you have to use either +## -O# where # <= 4 or one of (-fno-ommit-frame-pointer or -fno-force-mem) +## This bug is reportedly fixed in pgcc >1.0, but this was not tested +CFLAGS+=-fno-force-mem + +LDFLAGS=-s -L. -lzdll -Zcrtdll +LDSHARED=$(CC) -s -Zomf -Zdll -Zcrtdll + +VER=1.1.0 +ZLIB=z.lib +SHAREDLIB=z.dll +SHAREDLIBIMP=zdll.lib +LIBS=$(ZLIB) $(SHAREDLIB) $(SHAREDLIBIMP) + +AR=emxomfar cr +IMPLIB=emximp +RANLIB=echo +TAR=tar +SHELL=bash + +prefix=/usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \ + zutil.o inflate.o infblock.o inftrees.o infcodes.o infutil.o inffast.o + +TEST_OBJS = example.o minigzip.o + +DISTFILES = README INDEX ChangeLog configure Make*[a-z0-9] *.[ch] descrip.mms \ + algorithm.txt zlib.3 msdos/Make*[a-z0-9] msdos/zlib.def msdos/zlib.rc \ + nt/Makefile.nt nt/zlib.dnt contrib/README.contrib contrib/*.txt \ + contrib/asm386/*.asm contrib/asm386/*.c \ + contrib/asm386/*.bat contrib/asm386/zlibvc.d?? contrib/iostream/*.cpp \ + contrib/iostream/*.h contrib/iostream2/*.h contrib/iostream2/*.cpp \ + contrib/untgz/Makefile contrib/untgz/*.c contrib/untgz/*.w32 + +all: example.exe minigzip.exe + +test: all + @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \ + echo hello world | ./minigzip | ./minigzip -d || \ + echo ' *** minigzip test FAILED ***' ; \ + if ./example; then \ + echo ' *** zlib test OK ***'; \ + else \ + echo ' *** zlib test FAILED ***'; \ + fi + +$(ZLIB): $(OBJS) + $(AR) $@ $(OBJS) + -@ ($(RANLIB) $@ || true) >/dev/null 2>&1 + +$(SHAREDLIB): $(OBJS) os2/z.def + $(LDSHARED) -o $@ $^ + +$(SHAREDLIBIMP): os2/z.def + $(IMPLIB) -o $@ $^ + +example.exe: example.o $(LIBS) + $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS) + +minigzip.exe: minigzip.o $(LIBS) + $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS) + +clean: + rm -f *.o *~ example minigzip libz.a libz.so* foo.gz + +distclean: clean + +zip: + mv Makefile Makefile~; cp -p Makefile.in Makefile + rm -f test.c ztest*.c + v=`sed -n -e 's/\.//g' -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\ + zip -ul9 zlib$$v $(DISTFILES) + mv Makefile~ Makefile + +dist: + mv Makefile Makefile~; cp -p Makefile.in Makefile + rm -f test.c ztest*.c + d=zlib-`sed -n '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`;\ + rm -f $$d.tar.gz; \ + if test ! -d ../$$d; then rm -f ../$$d; ln -s `pwd` ../$$d; fi; \ + files=""; \ + for f in $(DISTFILES); do files="$$files $$d/$$f"; done; \ + cd ..; \ + GZIP=-9 $(TAR) chofz $$d/$$d.tar.gz $$files; \ + if test ! -d $$d; then rm -f $$d; fi + mv Makefile~ Makefile + +tags: + etags *.[ch] + +depend: + makedepend -- $(CFLAGS) -- *.[ch] + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +example.o: zlib.h zconf.h +gzio.o: zutil.h zlib.h zconf.h +infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h +infcodes.o: zutil.h zlib.h zconf.h +infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h +inffast.o: infblock.h infcodes.h infutil.h inffast.h +inflate.o: zutil.h zlib.h zconf.h infblock.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h +minigzip.o: zlib.h zconf.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/test/zlib/zlib-1.2.8/old/os2/zlib.def b/test/zlib/zlib-1.2.8/old/os2/zlib.def new file mode 100644 index 000000000..4c753f1a3 --- /dev/null +++ b/test/zlib/zlib-1.2.8/old/os2/zlib.def @@ -0,0 +1,51 @@ +; +; Slightly modified version of ../nt/zlib.dnt :-) +; + +LIBRARY Z +DESCRIPTION "Zlib compression library for OS/2" +CODE PRELOAD MOVEABLE DISCARDABLE +DATA PRELOAD MOVEABLE MULTIPLE + +EXPORTS + adler32 + compress + crc32 + deflate + deflateCopy + deflateEnd + deflateInit2_ + deflateInit_ + deflateParams + deflateReset + deflateSetDictionary + gzclose + gzdopen + gzerror + gzflush + gzopen + gzread + gzwrite + inflate + inflateEnd + inflateInit2_ + inflateInit_ + inflateReset + inflateSetDictionary + inflateSync + uncompress + zlibVersion + gzprintf + gzputc + gzgetc + gzseek + gzrewind + gztell + gzeof + gzsetparams + zError + inflateSyncPoint + get_crc_table + compress2 + gzputs + gzgets diff --git a/test/zlib/zlib-1.2.8/old/visual-basic.txt b/test/zlib/zlib-1.2.8/old/visual-basic.txt new file mode 100644 index 000000000..57efe5812 --- /dev/null +++ b/test/zlib/zlib-1.2.8/old/visual-basic.txt @@ -0,0 +1,160 @@ +See below some functions declarations for Visual Basic. + +Frequently Asked Question: + +Q: Each time I use the compress function I get the -5 error (not enough + room in the output buffer). + +A: Make sure that the length of the compressed buffer is passed by + reference ("as any"), not by value ("as long"). Also check that + before the call of compress this length is equal to the total size of + the compressed buffer and not zero. + + +From: "Jon Caruana" +Subject: Re: How to port zlib declares to vb? +Date: Mon, 28 Oct 1996 18:33:03 -0600 + +Got the answer! (I haven't had time to check this but it's what I got, and +looks correct): + +He has the following routines working: + compress + uncompress + gzopen + gzwrite + gzread + gzclose + +Declares follow: (Quoted from Carlos Rios , in Vb4 form) + +#If Win16 Then 'Use Win16 calls. +Declare Function compress Lib "ZLIB.DLL" (ByVal compr As + String, comprLen As Any, ByVal buf As String, ByVal buflen + As Long) As Integer +Declare Function uncompress Lib "ZLIB.DLL" (ByVal uncompr + As String, uncomprLen As Any, ByVal compr As String, ByVal + lcompr As Long) As Integer +Declare Function gzopen Lib "ZLIB.DLL" (ByVal filePath As + String, ByVal mode As String) As Long +Declare Function gzread Lib "ZLIB.DLL" (ByVal file As + Long, ByVal uncompr As String, ByVal uncomprLen As Integer) + As Integer +Declare Function gzwrite Lib "ZLIB.DLL" (ByVal file As + Long, ByVal uncompr As String, ByVal uncomprLen As Integer) + As Integer +Declare Function gzclose Lib "ZLIB.DLL" (ByVal file As + Long) As Integer +#Else +Declare Function compress Lib "ZLIB32.DLL" + (ByVal compr As String, comprLen As Any, ByVal buf As + String, ByVal buflen As Long) As Integer +Declare Function uncompress Lib "ZLIB32.DLL" + (ByVal uncompr As String, uncomprLen As Any, ByVal compr As + String, ByVal lcompr As Long) As Long +Declare Function gzopen Lib "ZLIB32.DLL" + (ByVal file As String, ByVal mode As String) As Long +Declare Function gzread Lib "ZLIB32.DLL" + (ByVal file As Long, ByVal uncompr As String, ByVal + uncomprLen As Long) As Long +Declare Function gzwrite Lib "ZLIB32.DLL" + (ByVal file As Long, ByVal uncompr As String, ByVal + uncomprLen As Long) As Long +Declare Function gzclose Lib "ZLIB32.DLL" + (ByVal file As Long) As Long +#End If + +-Jon Caruana +jon-net@usa.net +Microsoft Sitebuilder Network Level 1 Member - HTML Writer's Guild Member + + +Here is another example from Michael that he +says conforms to the VB guidelines, and that solves the problem of not +knowing the uncompressed size by storing it at the end of the file: + +'Calling the functions: +'bracket meaning: [optional] {Range of possible values} +'Call subCompressFile( [, , [level of compression {1..9}]]) +'Call subUncompressFile() + +Option Explicit +Private lngpvtPcnSml As Long 'Stores value for 'lngPercentSmaller' +Private Const SUCCESS As Long = 0 +Private Const strFilExt As String = ".cpr" +Private Declare Function lngfncCpr Lib "zlib.dll" Alias "compress2" (ByRef +dest As Any, ByRef destLen As Any, ByRef src As Any, ByVal srcLen As Long, +ByVal level As Integer) As Long +Private Declare Function lngfncUcp Lib "zlib.dll" Alias "uncompress" (ByRef +dest As Any, ByRef destLen As Any, ByRef src As Any, ByVal srcLen As Long) +As Long + +Public Sub subCompressFile(ByVal strargOriFilPth As String, Optional ByVal +strargCprFilPth As String, Optional ByVal intLvl As Integer = 9) + Dim strCprPth As String + Dim lngOriSiz As Long + Dim lngCprSiz As Long + Dim bytaryOri() As Byte + Dim bytaryCpr() As Byte + lngOriSiz = FileLen(strargOriFilPth) + ReDim bytaryOri(lngOriSiz - 1) + Open strargOriFilPth For Binary Access Read As #1 + Get #1, , bytaryOri() + Close #1 + strCprPth = IIf(strargCprFilPth = "", strargOriFilPth, strargCprFilPth) +'Select file path and name + strCprPth = strCprPth & IIf(Right(strCprPth, Len(strFilExt)) = +strFilExt, "", strFilExt) 'Add file extension if not exists + lngCprSiz = (lngOriSiz * 1.01) + 12 'Compression needs temporary a bit +more space then original file size + ReDim bytaryCpr(lngCprSiz - 1) + If lngfncCpr(bytaryCpr(0), lngCprSiz, bytaryOri(0), lngOriSiz, intLvl) = +SUCCESS Then + lngpvtPcnSml = (1# - (lngCprSiz / lngOriSiz)) * 100 + ReDim Preserve bytaryCpr(lngCprSiz - 1) + Open strCprPth For Binary Access Write As #1 + Put #1, , bytaryCpr() + Put #1, , lngOriSiz 'Add the the original size value to the end +(last 4 bytes) + Close #1 + Else + MsgBox "Compression error" + End If + Erase bytaryCpr + Erase bytaryOri +End Sub + +Public Sub subUncompressFile(ByVal strargFilPth As String) + Dim bytaryCpr() As Byte + Dim bytaryOri() As Byte + Dim lngOriSiz As Long + Dim lngCprSiz As Long + Dim strOriPth As String + lngCprSiz = FileLen(strargFilPth) + ReDim bytaryCpr(lngCprSiz - 1) + Open strargFilPth For Binary Access Read As #1 + Get #1, , bytaryCpr() + Close #1 + 'Read the original file size value: + lngOriSiz = bytaryCpr(lngCprSiz - 1) * (2 ^ 24) _ + + bytaryCpr(lngCprSiz - 2) * (2 ^ 16) _ + + bytaryCpr(lngCprSiz - 3) * (2 ^ 8) _ + + bytaryCpr(lngCprSiz - 4) + ReDim Preserve bytaryCpr(lngCprSiz - 5) 'Cut of the original size value + ReDim bytaryOri(lngOriSiz - 1) + If lngfncUcp(bytaryOri(0), lngOriSiz, bytaryCpr(0), lngCprSiz) = SUCCESS +Then + strOriPth = Left(strargFilPth, Len(strargFilPth) - Len(strFilExt)) + Open strOriPth For Binary Access Write As #1 + Put #1, , bytaryOri() + Close #1 + Else + MsgBox "Uncompression error" + End If + Erase bytaryCpr + Erase bytaryOri +End Sub +Public Property Get lngPercentSmaller() As Long + lngPercentSmaller = lngpvtPcnSml +End Property diff --git a/test/zlib/zlib-1.2.8/qnx/package.qpg b/test/zlib/zlib-1.2.8/qnx/package.qpg new file mode 100644 index 000000000..aebf6e3ac --- /dev/null +++ b/test/zlib/zlib-1.2.8/qnx/package.qpg @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Library + + Medium + + 2.0 + + + + zlib + zlib + alain.bonnefoy@icbt.com + Public + public + www.gzip.org/zlib + + + Jean-Loup Gailly,Mark Adler + www.gzip.org/zlib + + zlib@gzip.org + + + A massively spiffy yet delicately unobtrusive compression library. + zlib is designed to be a free, general-purpose, legally unencumbered, lossless data compression library for use on virtually any computer hardware and operating system. + http://www.gzip.org/zlib + + + + + 1.2.8 + Medium + Stable + + + + + + + No License + + + + Software Development/Libraries and Extensions/C Libraries + zlib,compression + qnx6 + qnx6 + None + Developer + + + + + + + + + + + + + + Install + Post + No + Ignore + + No + Optional + + + + + + + + + + + + + InstallOver + zlib + + + + + + + + + + + + + InstallOver + zlib-dev + + + + + + + + + diff --git a/test/zlib/zlib-1.2.8/test/example.c b/test/zlib/zlib-1.2.8/test/example.c new file mode 100644 index 000000000..138a699bd --- /dev/null +++ b/test/zlib/zlib-1.2.8/test/example.c @@ -0,0 +1,601 @@ +/* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-2006, 2011 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zlib.h" +#include + +#ifdef STDC +# include +# include +#endif + +#if defined(VMS) || defined(RISCOS) +# define TESTFILE "foo-gz" +#else +# define TESTFILE "foo.gz" +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +z_const char hello[] = "hello, hello!"; +/* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + */ + +const char dictionary[] = "hello"; +uLong dictId; /* Adler32 value of the dictionary */ + +void test_deflate OF((Byte *compr, uLong comprLen)); +void test_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_deflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_flush OF((Byte *compr, uLong *comprLen)); +void test_sync OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_dict_deflate OF((Byte *compr, uLong comprLen)); +void test_dict_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +int main OF((int argc, char *argv[])); + + +#ifdef Z_SOLO + +void *myalloc OF((void *, unsigned, unsigned)); +void myfree OF((void *, void *)); + +void *myalloc(q, n, m) + void *q; + unsigned n, m; +{ + q = Z_NULL; + return calloc(n, m); +} + +void myfree(void *q, void *p) +{ + q = Z_NULL; + free(p); +} + +static alloc_func zalloc = myalloc; +static free_func zfree = myfree; + +#else /* !Z_SOLO */ + +static alloc_func zalloc = (alloc_func)0; +static free_func zfree = (free_func)0; + +void test_compress OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_gzio OF((const char *fname, + Byte *uncompr, uLong uncomprLen)); + +/* =========================================================================== + * Test compress() and uncompress() + */ +void test_compress(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + uLong len = (uLong)strlen(hello)+1; + + err = compress(compr, &comprLen, (const Bytef*)hello, len); + CHECK_ERR(err, "compress"); + + strcpy((char*)uncompr, "garbage"); + + err = uncompress(uncompr, &uncomprLen, compr, comprLen); + CHECK_ERR(err, "uncompress"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad uncompress\n"); + exit(1); + } else { + printf("uncompress(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test read/write of .gz files + */ +void test_gzio(fname, uncompr, uncomprLen) + const char *fname; /* compressed file name */ + Byte *uncompr; + uLong uncomprLen; +{ +#ifdef NO_GZCOMPRESS + fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); +#else + int err; + int len = (int)strlen(hello)+1; + gzFile file; + z_off_t pos; + + file = gzopen(fname, "wb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + gzputc(file, 'h'); + if (gzputs(file, "ello") != 4) { + fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); + exit(1); + } + if (gzprintf(file, ", %s!", "hello") != 8) { + fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); + exit(1); + } + gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ + gzclose(file); + + file = gzopen(fname, "rb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + strcpy((char*)uncompr, "garbage"); + + if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { + fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); + exit(1); + } else { + printf("gzread(): %s\n", (char*)uncompr); + } + + pos = gzseek(file, -8L, SEEK_CUR); + if (pos != 6 || gztell(file) != pos) { + fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", + (long)pos, (long)gztell(file)); + exit(1); + } + + if (gzgetc(file) != ' ') { + fprintf(stderr, "gzgetc error\n"); + exit(1); + } + + if (gzungetc(' ', file) != ' ') { + fprintf(stderr, "gzungetc error\n"); + exit(1); + } + + gzgets(file, (char*)uncompr, (int)uncomprLen); + if (strlen((char*)uncompr) != 7) { /* " hello!" */ + fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); + exit(1); + } + if (strcmp((char*)uncompr, hello + 6)) { + fprintf(stderr, "bad gzgets after gzseek\n"); + exit(1); + } else { + printf("gzgets() after gzseek: %s\n", (char*)uncompr); + } + + gzclose(file); +#endif +} + +#endif /* Z_SOLO */ + +/* =========================================================================== + * Test deflate() with small buffers + */ +void test_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uLong len = (uLong)strlen(hello)+1; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = deflate(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with small buffers + */ +void test_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 0; + d_stream.next_out = uncompr; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate\n"); + exit(1); + } else { + printf("inflate(): %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Test deflate() with large buffers and dynamic change of compression level + */ +void test_large_deflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_SPEED); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + /* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + */ + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + if (c_stream.avail_in != 0) { + fprintf(stderr, "deflate not greedy\n"); + exit(1); + } + + /* Feed in already compressed data and switch to no compression: */ + deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in = compr; + c_stream.avail_in = (uInt)comprLen/2; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + /* Switch back to compressing mode: */ + deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with large buffers + */ +void test_large_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = (uInt)uncomprLen; + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "large inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (d_stream.total_out != 2*uncomprLen + comprLen/2) { + fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); + exit(1); + } else { + printf("large_inflate(): OK\n"); + } +} + +/* =========================================================================== + * Test deflate() with full flush + */ +void test_flush(compr, comprLen) + Byte *compr; + uLong *comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + uInt len = (uInt)strlen(hello)+1; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (uInt)*comprLen; + err = deflate(&c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, "deflate"); + + compr[3]++; /* force an error in first compressed block */ + c_stream.avail_in = len - 3; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + CHECK_ERR(err, "deflate"); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); + + *comprLen = c_stream.total_out; +} + +/* =========================================================================== + * Test inflateSync() + */ +void test_sync(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = 2; /* just read the zlib header */ + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + inflate(&d_stream, Z_NO_FLUSH); + CHECK_ERR(err, "inflate"); + + d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ + err = inflateSync(&d_stream); /* but skip the damaged part */ + CHECK_ERR(err, "inflateSync"); + + err = inflate(&d_stream, Z_FINISH); + if (err != Z_DATA_ERROR) { + fprintf(stderr, "inflate should report DATA_ERROR\n"); + /* Because of incorrect adler32 */ + exit(1); + } + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + printf("after inflateSync(): hel%s\n", (char *)uncompr); +} + +/* =========================================================================== + * Test deflate() with preset dictionary + */ +void test_dict_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = zalloc; + c_stream.zfree = zfree; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + err = deflateSetDictionary(&c_stream, + (const Bytef*)dictionary, (int)sizeof(dictionary)); + CHECK_ERR(err, "deflateSetDictionary"); + + dictId = c_stream.adler; + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + c_stream.next_in = (z_const unsigned char *)hello; + c_stream.avail_in = (uInt)strlen(hello)+1; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + exit(1); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with a preset dictionary + */ +void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = zalloc; + d_stream.zfree = zfree; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + for (;;) { + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if (err == Z_NEED_DICT) { + if (d_stream.adler != dictId) { + fprintf(stderr, "unexpected dictionary"); + exit(1); + } + err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, + (int)sizeof(dictionary)); + } + CHECK_ERR(err, "inflate with dict"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate with dict\n"); + exit(1); + } else { + printf("inflate with dictionary: %s\n", (char *)uncompr); + } +} + +/* =========================================================================== + * Usage: example [output.gz [input.gz]] + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + Byte *compr, *uncompr; + uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ + uLong uncomprLen = comprLen; + static const char* myVersion = ZLIB_VERSION; + + if (zlibVersion()[0] != myVersion[0]) { + fprintf(stderr, "incompatible zlib version\n"); + exit(1); + + } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { + fprintf(stderr, "warning: different zlib version\n"); + } + + printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n", + ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags()); + + compr = (Byte*)calloc((uInt)comprLen, 1); + uncompr = (Byte*)calloc((uInt)uncomprLen, 1); + /* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + */ + if (compr == Z_NULL || uncompr == Z_NULL) { + printf("out of memory\n"); + exit(1); + } + +#ifdef Z_SOLO + argc = strlen(argv[0]); +#else + test_compress(compr, comprLen, uncompr, uncomprLen); + + test_gzio((argc > 1 ? argv[1] : TESTFILE), + uncompr, uncomprLen); +#endif + + test_deflate(compr, comprLen); + test_inflate(compr, comprLen, uncompr, uncomprLen); + + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + + test_flush(compr, &comprLen); + test_sync(compr, comprLen, uncompr, uncomprLen); + comprLen = uncomprLen; + + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + + free(compr); + free(uncompr); + + return 0; +} diff --git a/test/zlib/zlib-1.2.8/test/infcover.c b/test/zlib/zlib-1.2.8/test/infcover.c new file mode 100644 index 000000000..fe3d9203a --- /dev/null +++ b/test/zlib/zlib-1.2.8/test/infcover.c @@ -0,0 +1,671 @@ +/* infcover.c -- test zlib's inflate routines with full code coverage + * Copyright (C) 2011 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* to use, do: ./configure --cover && make cover */ + +#include +#include +#include +#include +#include "zlib.h" + +/* get definition of internal structure so we can mess with it (see pull()), + and so we can call inflate_trees() (see cover5()) */ +#define ZLIB_INTERNAL +#include "inftrees.h" +#include "inflate.h" + +#define local static + +/* -- memory tracking routines -- */ + +/* + These memory tracking routines are provided to zlib and track all of zlib's + allocations and deallocations, check for LIFO operations, keep a current + and high water mark of total bytes requested, optionally set a limit on the + total memory that can be allocated, and when done check for memory leaks. + + They are used as follows: + + z_stream strm; + mem_setup(&strm) initializes the memory tracking and sets the + zalloc, zfree, and opaque members of strm to use + memory tracking for all zlib operations on strm + mem_limit(&strm, limit) sets a limit on the total bytes requested -- a + request that exceeds this limit will result in an + allocation failure (returns NULL) -- setting the + limit to zero means no limit, which is the default + after mem_setup() + mem_used(&strm, "msg") prints to stderr "msg" and the total bytes used + mem_high(&strm, "msg") prints to stderr "msg" and the high water mark + mem_done(&strm, "msg") ends memory tracking, releases all allocations + for the tracking as well as leaked zlib blocks, if + any. If there was anything unusual, such as leaked + blocks, non-FIFO frees, or frees of addresses not + allocated, then "msg" and information about the + problem is printed to stderr. If everything is + normal, nothing is printed. mem_done resets the + strm members to Z_NULL to use the default memory + allocation routines on the next zlib initialization + using strm. + */ + +/* these items are strung together in a linked list, one for each allocation */ +struct mem_item { + void *ptr; /* pointer to allocated memory */ + size_t size; /* requested size of allocation */ + struct mem_item *next; /* pointer to next item in list, or NULL */ +}; + +/* this structure is at the root of the linked list, and tracks statistics */ +struct mem_zone { + struct mem_item *first; /* pointer to first item in list, or NULL */ + size_t total, highwater; /* total allocations, and largest total */ + size_t limit; /* memory allocation limit, or 0 if no limit */ + int notlifo, rogue; /* counts of non-LIFO frees and rogue frees */ +}; + +/* memory allocation routine to pass to zlib */ +local void *mem_alloc(void *mem, unsigned count, unsigned size) +{ + void *ptr; + struct mem_item *item; + struct mem_zone *zone = mem; + size_t len = count * (size_t)size; + + /* induced allocation failure */ + if (zone == NULL || (zone->limit && zone->total + len > zone->limit)) + return NULL; + + /* perform allocation using the standard library, fill memory with a + non-zero value to make sure that the code isn't depending on zeros */ + ptr = malloc(len); + if (ptr == NULL) + return NULL; + memset(ptr, 0xa5, len); + + /* create a new item for the list */ + item = malloc(sizeof(struct mem_item)); + if (item == NULL) { + free(ptr); + return NULL; + } + item->ptr = ptr; + item->size = len; + + /* insert item at the beginning of the list */ + item->next = zone->first; + zone->first = item; + + /* update the statistics */ + zone->total += item->size; + if (zone->total > zone->highwater) + zone->highwater = zone->total; + + /* return the allocated memory */ + return ptr; +} + +/* memory free routine to pass to zlib */ +local void mem_free(void *mem, void *ptr) +{ + struct mem_item *item, *next; + struct mem_zone *zone = mem; + + /* if no zone, just do a free */ + if (zone == NULL) { + free(ptr); + return; + } + + /* point next to the item that matches ptr, or NULL if not found -- remove + the item from the linked list if found */ + next = zone->first; + if (next) { + if (next->ptr == ptr) + zone->first = next->next; /* first one is it, remove from list */ + else { + do { /* search the linked list */ + item = next; + next = item->next; + } while (next != NULL && next->ptr != ptr); + if (next) { /* if found, remove from linked list */ + item->next = next->next; + zone->notlifo++; /* not a LIFO free */ + } + + } + } + + /* if found, update the statistics and free the item */ + if (next) { + zone->total -= next->size; + free(next); + } + + /* if not found, update the rogue count */ + else + zone->rogue++; + + /* in any case, do the requested free with the standard library function */ + free(ptr); +} + +/* set up a controlled memory allocation space for monitoring, set the stream + parameters to the controlled routines, with opaque pointing to the space */ +local void mem_setup(z_stream *strm) +{ + struct mem_zone *zone; + + zone = malloc(sizeof(struct mem_zone)); + assert(zone != NULL); + zone->first = NULL; + zone->total = 0; + zone->highwater = 0; + zone->limit = 0; + zone->notlifo = 0; + zone->rogue = 0; + strm->opaque = zone; + strm->zalloc = mem_alloc; + strm->zfree = mem_free; +} + +/* set a limit on the total memory allocation, or 0 to remove the limit */ +local void mem_limit(z_stream *strm, size_t limit) +{ + struct mem_zone *zone = strm->opaque; + + zone->limit = limit; +} + +/* show the current total requested allocations in bytes */ +local void mem_used(z_stream *strm, char *prefix) +{ + struct mem_zone *zone = strm->opaque; + + fprintf(stderr, "%s: %lu allocated\n", prefix, zone->total); +} + +/* show the high water allocation in bytes */ +local void mem_high(z_stream *strm, char *prefix) +{ + struct mem_zone *zone = strm->opaque; + + fprintf(stderr, "%s: %lu high water mark\n", prefix, zone->highwater); +} + +/* release the memory allocation zone -- if there are any surprises, notify */ +local void mem_done(z_stream *strm, char *prefix) +{ + int count = 0; + struct mem_item *item, *next; + struct mem_zone *zone = strm->opaque; + + /* show high water mark */ + mem_high(strm, prefix); + + /* free leftover allocations and item structures, if any */ + item = zone->first; + while (item != NULL) { + free(item->ptr); + next = item->next; + free(item); + item = next; + count++; + } + + /* issue alerts about anything unexpected */ + if (count || zone->total) + fprintf(stderr, "** %s: %lu bytes in %d blocks not freed\n", + prefix, zone->total, count); + if (zone->notlifo) + fprintf(stderr, "** %s: %d frees not LIFO\n", prefix, zone->notlifo); + if (zone->rogue) + fprintf(stderr, "** %s: %d frees not recognized\n", + prefix, zone->rogue); + + /* free the zone and delete from the stream */ + free(zone); + strm->opaque = Z_NULL; + strm->zalloc = Z_NULL; + strm->zfree = Z_NULL; +} + +/* -- inflate test routines -- */ + +/* Decode a hexadecimal string, set *len to length, in[] to the bytes. This + decodes liberally, in that hex digits can be adjacent, in which case two in + a row writes a byte. Or they can delimited by any non-hex character, where + the delimiters are ignored except when a single hex digit is followed by a + delimiter in which case that single digit writes a byte. The returned + data is allocated and must eventually be freed. NULL is returned if out of + memory. If the length is not needed, then len can be NULL. */ +local unsigned char *h2b(const char *hex, unsigned *len) +{ + unsigned char *in; + unsigned next, val; + + in = malloc((strlen(hex) + 1) >> 1); + if (in == NULL) + return NULL; + next = 0; + val = 1; + do { + if (*hex >= '0' && *hex <= '9') + val = (val << 4) + *hex - '0'; + else if (*hex >= 'A' && *hex <= 'F') + val = (val << 4) + *hex - 'A' + 10; + else if (*hex >= 'a' && *hex <= 'f') + val = (val << 4) + *hex - 'a' + 10; + else if (val != 1 && val < 32) /* one digit followed by delimiter */ + val += 240; /* make it look like two digits */ + if (val > 255) { /* have two digits */ + in[next++] = val & 0xff; /* save the decoded byte */ + val = 1; /* start over */ + } + } while (*hex++); /* go through the loop with the terminating null */ + if (len != NULL) + *len = next; + in = reallocf(in, next); + return in; +} + +/* generic inflate() run, where hex is the hexadecimal input data, what is the + text to include in an error message, step is how much input data to feed + inflate() on each call, or zero to feed it all, win is the window bits + parameter to inflateInit2(), len is the size of the output buffer, and err + is the error code expected from the first inflate() call (the second + inflate() call is expected to return Z_STREAM_END). If win is 47, then + header information is collected with inflateGetHeader(). If a zlib stream + is looking for a dictionary, then an empty dictionary is provided. + inflate() is run until all of the input data is consumed. */ +local void inf(char *hex, char *what, unsigned step, int win, unsigned len, + int err) +{ + int ret; + unsigned have; + unsigned char *in, *out; + z_stream strm, copy; + gz_header head; + + mem_setup(&strm); + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, win); + if (ret != Z_OK) { + mem_done(&strm, what); + return; + } + out = malloc(len); assert(out != NULL); + if (win == 47) { + head.extra = out; + head.extra_max = len; + head.name = out; + head.name_max = len; + head.comment = out; + head.comm_max = len; + ret = inflateGetHeader(&strm, &head); assert(ret == Z_OK); + } + in = h2b(hex, &have); assert(in != NULL); + if (step == 0 || step > have) + step = have; + strm.avail_in = step; + have -= step; + strm.next_in = in; + do { + strm.avail_out = len; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); assert(err == 9 || ret == err); + if (ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_NEED_DICT) + break; + if (ret == Z_NEED_DICT) { + ret = inflateSetDictionary(&strm, in, 1); + assert(ret == Z_DATA_ERROR); + mem_limit(&strm, 1); + ret = inflateSetDictionary(&strm, out, 0); + assert(ret == Z_MEM_ERROR); + mem_limit(&strm, 0); + ((struct inflate_state *)strm.state)->mode = DICT; + ret = inflateSetDictionary(&strm, out, 0); + assert(ret == Z_OK); + ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_BUF_ERROR); + } + ret = inflateCopy(©, &strm); assert(ret == Z_OK); + ret = inflateEnd(©); assert(ret == Z_OK); + err = 9; /* don't care next time around */ + have += strm.avail_in; + strm.avail_in = step > have ? have : step; + have -= strm.avail_in; + } while (strm.avail_in); + free(in); + free(out); + ret = inflateReset2(&strm, -8); assert(ret == Z_OK); + ret = inflateEnd(&strm); assert(ret == Z_OK); + mem_done(&strm, what); +} + +/* cover all of the lines in inflate.c up to inflate() */ +local void cover_support(void) +{ + int ret; + z_stream strm; + + mem_setup(&strm); + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); assert(ret == Z_OK); + mem_used(&strm, "inflate init"); + ret = inflatePrime(&strm, 5, 31); assert(ret == Z_OK); + ret = inflatePrime(&strm, -1, 0); assert(ret == Z_OK); + ret = inflateSetDictionary(&strm, Z_NULL, 0); + assert(ret == Z_STREAM_ERROR); + ret = inflateEnd(&strm); assert(ret == Z_OK); + mem_done(&strm, "prime"); + + inf("63 0", "force window allocation", 0, -15, 1, Z_OK); + inf("63 18 5", "force window replacement", 0, -8, 259, Z_OK); + inf("63 18 68 30 d0 0 0", "force split window update", 4, -8, 259, Z_OK); + inf("3 0", "use fixed blocks", 0, -15, 1, Z_STREAM_END); + inf("", "bad window size", 0, 1, 0, Z_STREAM_ERROR); + + mem_setup(&strm); + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit_(&strm, ZLIB_VERSION - 1, (int)sizeof(z_stream)); + assert(ret == Z_VERSION_ERROR); + mem_done(&strm, "wrong version"); + + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit(&strm); assert(ret == Z_OK); + ret = inflateEnd(&strm); assert(ret == Z_OK); + fputs("inflate built-in memory routines\n", stderr); +} + +/* cover all inflate() header and trailer cases and code after inflate() */ +local void cover_wrap(void) +{ + int ret; + z_stream strm, copy; + unsigned char dict[257]; + + ret = inflate(Z_NULL, 0); assert(ret == Z_STREAM_ERROR); + ret = inflateEnd(Z_NULL); assert(ret == Z_STREAM_ERROR); + ret = inflateCopy(Z_NULL, Z_NULL); assert(ret == Z_STREAM_ERROR); + fputs("inflate bad parameters\n", stderr); + + inf("1f 8b 0 0", "bad gzip method", 0, 31, 0, Z_DATA_ERROR); + inf("1f 8b 8 80", "bad gzip flags", 0, 31, 0, Z_DATA_ERROR); + inf("77 85", "bad zlib method", 0, 15, 0, Z_DATA_ERROR); + inf("8 99", "set window size from header", 0, 0, 0, Z_OK); + inf("78 9c", "bad zlib window size", 0, 8, 0, Z_DATA_ERROR); + inf("78 9c 63 0 0 0 1 0 1", "check adler32", 0, 15, 1, Z_STREAM_END); + inf("1f 8b 8 1e 0 0 0 0 0 0 1 0 0 0 0 0 0", "bad header crc", 0, 47, 1, + Z_DATA_ERROR); + inf("1f 8b 8 2 0 0 0 0 0 0 1d 26 3 0 0 0 0 0 0 0 0 0", "check gzip length", + 0, 47, 0, Z_STREAM_END); + inf("78 90", "bad zlib header check", 0, 47, 0, Z_DATA_ERROR); + inf("8 b8 0 0 0 1", "need dictionary", 0, 8, 0, Z_NEED_DICT); + inf("78 9c 63 0", "compute adler32", 0, 15, 1, Z_OK); + + mem_setup(&strm); + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, -8); + strm.avail_in = 2; + strm.next_in = (void *)"\x63"; + strm.avail_out = 1; + strm.next_out = (void *)&ret; + mem_limit(&strm, 1); + ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_MEM_ERROR); + ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_MEM_ERROR); + mem_limit(&strm, 0); + memset(dict, 0, 257); + ret = inflateSetDictionary(&strm, dict, 257); + assert(ret == Z_OK); + mem_limit(&strm, (sizeof(struct inflate_state) << 1) + 256); + ret = inflatePrime(&strm, 16, 0); assert(ret == Z_OK); + strm.avail_in = 2; + strm.next_in = (void *)"\x80"; + ret = inflateSync(&strm); assert(ret == Z_DATA_ERROR); + ret = inflate(&strm, Z_NO_FLUSH); assert(ret == Z_STREAM_ERROR); + strm.avail_in = 4; + strm.next_in = (void *)"\0\0\xff\xff"; + ret = inflateSync(&strm); assert(ret == Z_OK); + (void)inflateSyncPoint(&strm); + ret = inflateCopy(©, &strm); assert(ret == Z_MEM_ERROR); + mem_limit(&strm, 0); + ret = inflateUndermine(&strm, 1); assert(ret == Z_DATA_ERROR); + (void)inflateMark(&strm); + ret = inflateEnd(&strm); assert(ret == Z_OK); + mem_done(&strm, "miscellaneous, force memory errors"); +} + +/* input and output functions for inflateBack() */ +local unsigned pull(void *desc, unsigned char **buf) +{ + static unsigned int next = 0; + static unsigned char dat[] = {0x63, 0, 2, 0}; + struct inflate_state *state; + + if (desc == Z_NULL) { + next = 0; + return 0; /* no input (already provided at next_in) */ + } + state = (void *)((z_stream *)desc)->state; + if (state != Z_NULL) + state->mode = SYNC; /* force an otherwise impossible situation */ + return next < sizeof(dat) ? (*buf = dat + next++, 1) : 0; +} + +local int push(void *desc, unsigned char *buf, unsigned len) +{ + buf += len; + return desc != Z_NULL; /* force error if desc not null */ +} + +/* cover inflateBack() up to common deflate data cases and after those */ +local void cover_back(void) +{ + int ret; + z_stream strm; + unsigned char win[32768]; + + ret = inflateBackInit_(Z_NULL, 0, win, 0, 0); + assert(ret == Z_VERSION_ERROR); + ret = inflateBackInit(Z_NULL, 0, win); assert(ret == Z_STREAM_ERROR); + ret = inflateBack(Z_NULL, Z_NULL, Z_NULL, Z_NULL, Z_NULL); + assert(ret == Z_STREAM_ERROR); + ret = inflateBackEnd(Z_NULL); assert(ret == Z_STREAM_ERROR); + fputs("inflateBack bad parameters\n", stderr); + + mem_setup(&strm); + ret = inflateBackInit(&strm, 15, win); assert(ret == Z_OK); + strm.avail_in = 2; + strm.next_in = (void *)"\x03"; + ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL); + assert(ret == Z_STREAM_END); + /* force output error */ + strm.avail_in = 3; + strm.next_in = (void *)"\x63\x00"; + ret = inflateBack(&strm, pull, Z_NULL, push, &strm); + assert(ret == Z_BUF_ERROR); + /* force mode error by mucking with state */ + ret = inflateBack(&strm, pull, &strm, push, Z_NULL); + assert(ret == Z_STREAM_ERROR); + ret = inflateBackEnd(&strm); assert(ret == Z_OK); + mem_done(&strm, "inflateBack bad state"); + + ret = inflateBackInit(&strm, 15, win); assert(ret == Z_OK); + ret = inflateBackEnd(&strm); assert(ret == Z_OK); + fputs("inflateBack built-in memory routines\n", stderr); +} + +/* do a raw inflate of data in hexadecimal with both inflate and inflateBack */ +local int try(char *hex, char *id, int err) +{ + int ret; + unsigned len, size; + unsigned char *in, *out, *win; + char *prefix; + z_stream strm; + + /* convert to hex */ + in = h2b(hex, &len); + assert(in != NULL); + + /* allocate work areas */ + size = len << 3; + out = malloc(size); + assert(out != NULL); + win = malloc(32768); + assert(win != NULL); + prefix = malloc(strlen(id) + 6); + assert(prefix != NULL); + + /* first with inflate */ + strcpy(prefix, id); + strcat(prefix, "-late"); + mem_setup(&strm); + strm.avail_in = 0; + strm.next_in = Z_NULL; + ret = inflateInit2(&strm, err < 0 ? 47 : -15); + assert(ret == Z_OK); + strm.avail_in = len; + strm.next_in = in; + do { + strm.avail_out = size; + strm.next_out = out; + ret = inflate(&strm, Z_TREES); + assert(ret != Z_STREAM_ERROR && ret != Z_MEM_ERROR); + if (ret == Z_DATA_ERROR || ret == Z_NEED_DICT) + break; + } while (strm.avail_in || strm.avail_out == 0); + if (err) { + assert(ret == Z_DATA_ERROR); + assert(strcmp(id, strm.msg) == 0); + } + inflateEnd(&strm); + mem_done(&strm, prefix); + + /* then with inflateBack */ + if (err >= 0) { + strcpy(prefix, id); + strcat(prefix, "-back"); + mem_setup(&strm); + ret = inflateBackInit(&strm, 15, win); + assert(ret == Z_OK); + strm.avail_in = len; + strm.next_in = in; + ret = inflateBack(&strm, pull, Z_NULL, push, Z_NULL); + assert(ret != Z_STREAM_ERROR); + if (err) { + assert(ret == Z_DATA_ERROR); + assert(strcmp(id, strm.msg) == 0); + } + inflateBackEnd(&strm); + mem_done(&strm, prefix); + } + + /* clean up */ + free(prefix); + free(win); + free(out); + free(in); + return ret; +} + +/* cover deflate data cases in both inflate() and inflateBack() */ +local void cover_inflate(void) +{ + try("0 0 0 0 0", "invalid stored block lengths", 1); + try("3 0", "fixed", 0); + try("6", "invalid block type", 1); + try("1 1 0 fe ff 0", "stored", 0); + try("fc 0 0", "too many length or distance symbols", 1); + try("4 0 fe ff", "invalid code lengths set", 1); + try("4 0 24 49 0", "invalid bit length repeat", 1); + try("4 0 24 e9 ff ff", "invalid bit length repeat", 1); + try("4 0 24 e9 ff 6d", "invalid code -- missing end-of-block", 1); + try("4 80 49 92 24 49 92 24 71 ff ff 93 11 0", + "invalid literal/lengths set", 1); + try("4 80 49 92 24 49 92 24 f b4 ff ff c3 84", "invalid distances set", 1); + try("4 c0 81 8 0 0 0 0 20 7f eb b 0 0", "invalid literal/length code", 1); + try("2 7e ff ff", "invalid distance code", 1); + try("c c0 81 0 0 0 0 0 90 ff 6b 4 0", "invalid distance too far back", 1); + + /* also trailer mismatch just in inflate() */ + try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 1", "incorrect data check", -1); + try("1f 8b 8 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 1", + "incorrect length check", -1); + try("5 c0 21 d 0 0 0 80 b0 fe 6d 2f 91 6c", "pull 17", 0); + try("5 e0 81 91 24 cb b2 2c 49 e2 f 2e 8b 9a 47 56 9f fb fe ec d2 ff 1f", + "long code", 0); + try("ed c0 1 1 0 0 0 40 20 ff 57 1b 42 2c 4f", "length extra", 0); + try("ed cf c1 b1 2c 47 10 c4 30 fa 6f 35 1d 1 82 59 3d fb be 2e 2a fc f c", + "long distance and extra", 0); + try("ed c0 81 0 0 0 0 80 a0 fd a9 17 a9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 " + "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 6", "window end", 0); + inf("2 8 20 80 0 3 0", "inflate_fast TYPE return", 0, -15, 258, + Z_STREAM_END); + inf("63 18 5 40 c 0", "window wrap", 3, -8, 300, Z_OK); +} + +/* cover remaining lines in inftrees.c */ +local void cover_trees(void) +{ + int ret; + unsigned bits; + unsigned short lens[16], work[16]; + code *next, table[ENOUGH_DISTS]; + + /* we need to call inflate_table() directly in order to manifest not- + enough errors, since zlib insures that enough is always enough */ + for (bits = 0; bits < 15; bits++) + lens[bits] = (unsigned short)(bits + 1); + lens[15] = 15; + next = table; + bits = 15; + ret = inflate_table(DISTS, lens, 16, &next, &bits, work); + assert(ret == 1); + next = table; + bits = 1; + ret = inflate_table(DISTS, lens, 16, &next, &bits, work); + assert(ret == 1); + fputs("inflate_table not enough errors\n", stderr); +} + +/* cover remaining inffast.c decoding and window copying */ +local void cover_fast(void) +{ + inf("e5 e0 81 ad 6d cb b2 2c c9 01 1e 59 63 ae 7d ee fb 4d fd b5 35 41 68" + " ff 7f 0f 0 0 0", "fast length extra bits", 0, -8, 258, Z_DATA_ERROR); + inf("25 fd 81 b5 6d 59 b6 6a 49 ea af 35 6 34 eb 8c b9 f6 b9 1e ef 67 49" + " 50 fe ff ff 3f 0 0", "fast distance extra bits", 0, -8, 258, + Z_DATA_ERROR); + inf("3 7e 0 0 0 0 0", "fast invalid distance code", 0, -8, 258, + Z_DATA_ERROR); + inf("1b 7 0 0 0 0 0", "fast invalid literal/length code", 0, -8, 258, + Z_DATA_ERROR); + inf("d c7 1 ae eb 38 c 4 41 a0 87 72 de df fb 1f b8 36 b1 38 5d ff ff 0", + "fast 2nd level codes and too far back", 0, -8, 258, Z_DATA_ERROR); + inf("63 18 5 8c 10 8 0 0 0 0", "very common case", 0, -8, 259, Z_OK); + inf("63 60 60 18 c9 0 8 18 18 18 26 c0 28 0 29 0 0 0", + "contiguous and wrap around window", 6, -8, 259, Z_OK); + inf("63 0 3 0 0 0 0 0", "copy direct from output", 0, -8, 259, + Z_STREAM_END); +} + +int main(void) +{ + fprintf(stderr, "%s\n", zlibVersion()); + cover_support(); + cover_wrap(); + cover_back(); + cover_inflate(); + cover_trees(); + cover_fast(); + return 0; +} diff --git a/test/zlib/zlib-1.2.8/test/minigzip.c b/test/zlib/zlib-1.2.8/test/minigzip.c new file mode 100644 index 000000000..b3025a489 --- /dev/null +++ b/test/zlib/zlib-1.2.8/test/minigzip.c @@ -0,0 +1,651 @@ +/* minigzip.c -- simulate gzip using the zlib compression library + * Copyright (C) 1995-2006, 2010, 2011 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * minigzip is a minimal implementation of the gzip utility. This is + * only an example of using zlib and isn't meant to replace the + * full-featured gzip. No attempt is made to deal with file systems + * limiting names to 14 or 8+3 characters, etc... Error checking is + * very limited. So use minigzip only for testing; use gzip for the + * real thing. On MSDOS, use only on file names without extension + * or in pipe mode. + */ + +/* @(#) $Id$ */ + +#include "zlib.h" +#include + +#ifdef STDC +# include +# include +#endif + +#ifdef USE_MMAP +# include +# include +# include +#endif + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__) +# include +# include +# ifdef UNDER_CE +# include +# endif +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#ifdef _MSC_VER +# define snprintf _snprintf +#endif + +#ifdef VMS +# define unlink delete +# define GZ_SUFFIX "-gz" +#endif +#ifdef RISCOS +# define unlink remove +# define GZ_SUFFIX "-gz" +# define fileno(file) file->__file +#endif +#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fileno */ +#endif + +#if !defined(Z_HAVE_UNISTD_H) && !defined(_LARGEFILE64_SOURCE) +#ifndef WIN32 /* unlink already in stdio.h for WIN32 */ + extern int unlink OF((const char *)); +#endif +#endif + +#if defined(UNDER_CE) +# include +# define perror(s) pwinerror(s) + +/* Map the Windows error number in ERROR to a locale-dependent error + message string and return a pointer to it. Typically, the values + for ERROR come from GetLastError. + + The string pointed to shall not be modified by the application, + but may be overwritten by a subsequent call to strwinerror + + The strwinerror function does not change the current setting + of GetLastError. */ + +static char *strwinerror (error) + DWORD error; +{ + static char buf[1024]; + + wchar_t *msgbuf; + DWORD lasterr = GetLastError(); + DWORD chars = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_ALLOCATE_BUFFER, + NULL, + error, + 0, /* Default language */ + (LPVOID)&msgbuf, + 0, + NULL); + if (chars != 0) { + /* If there is an \r\n appended, zap it. */ + if (chars >= 2 + && msgbuf[chars - 2] == '\r' && msgbuf[chars - 1] == '\n') { + chars -= 2; + msgbuf[chars] = 0; + } + + if (chars > sizeof (buf) - 1) { + chars = sizeof (buf) - 1; + msgbuf[chars] = 0; + } + + wcstombs(buf, msgbuf, chars + 1); + LocalFree(msgbuf); + } + else { + sprintf(buf, "unknown win32 error (%ld)", error); + } + + SetLastError(lasterr); + return buf; +} + +static void pwinerror (s) + const char *s; +{ + if (s && *s) + fprintf(stderr, "%s: %s\n", s, strwinerror(GetLastError ())); + else + fprintf(stderr, "%s\n", strwinerror(GetLastError ())); +} + +#endif /* UNDER_CE */ + +#ifndef GZ_SUFFIX +# define GZ_SUFFIX ".gz" +#endif +#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1) + +#define BUFLEN 16384 +#define MAX_NAME_LEN 1024 + +#ifdef MAXSEG_64K +# define local static + /* Needed for systems with limitation on stack size. */ +#else +# define local +#endif + +#ifdef Z_SOLO +/* for Z_SOLO, create simplified gz* functions using deflate and inflate */ + +#if defined(Z_HAVE_UNISTD_H) || defined(Z_LARGE) +# include /* for unlink() */ +#endif + +void *myalloc OF((void *, unsigned, unsigned)); +void myfree OF((void *, void *)); + +void *myalloc(q, n, m) + void *q; + unsigned n, m; +{ + q = Z_NULL; + return calloc(n, m); +} + +void myfree(q, p) + void *q, *p; +{ + q = Z_NULL; + free(p); +} + +typedef struct gzFile_s { + FILE *file; + int write; + int err; + char *msg; + z_stream strm; +} *gzFile; + +gzFile gzopen OF((const char *, const char *)); +gzFile gzdopen OF((int, const char *)); +gzFile gz_open OF((const char *, int, const char *)); + +gzFile gzopen(path, mode) +const char *path; +const char *mode; +{ + return gz_open(path, -1, mode); +} + +gzFile gzdopen(fd, mode) +int fd; +const char *mode; +{ + return gz_open(NULL, fd, mode); +} + +gzFile gz_open(path, fd, mode) + const char *path; + int fd; + const char *mode; +{ + gzFile gz; + int ret; + + gz = malloc(sizeof(struct gzFile_s)); + if (gz == NULL) + return NULL; + gz->write = strchr(mode, 'w') != NULL; + gz->strm.zalloc = myalloc; + gz->strm.zfree = myfree; + gz->strm.opaque = Z_NULL; + if (gz->write) + ret = deflateInit2(&(gz->strm), -1, 8, 15 + 16, 8, 0); + else { + gz->strm.next_in = 0; + gz->strm.avail_in = Z_NULL; + ret = inflateInit2(&(gz->strm), 15 + 16); + } + if (ret != Z_OK) { + free(gz); + return NULL; + } + gz->file = path == NULL ? fdopen(fd, gz->write ? "wb" : "rb") : + fopen(path, gz->write ? "wb" : "rb"); + if (gz->file == NULL) { + gz->write ? deflateEnd(&(gz->strm)) : inflateEnd(&(gz->strm)); + free(gz); + return NULL; + } + gz->err = 0; + gz->msg = ""; + return gz; +} + +int gzwrite OF((gzFile, const void *, unsigned)); + +int gzwrite(gz, buf, len) + gzFile gz; + const void *buf; + unsigned len; +{ + z_stream *strm; + unsigned char out[BUFLEN]; + + if (gz == NULL || !gz->write) + return 0; + strm = &(gz->strm); + strm->next_in = (void *)buf; + strm->avail_in = len; + do { + strm->next_out = out; + strm->avail_out = BUFLEN; + (void)deflate(strm, Z_NO_FLUSH); + fwrite(out, 1, BUFLEN - strm->avail_out, gz->file); + } while (strm->avail_out == 0); + return len; +} + +int gzread OF((gzFile, void *, unsigned)); + +int gzread(gz, buf, len) + gzFile gz; + void *buf; + unsigned len; +{ + int ret; + unsigned got; + unsigned char in[1]; + z_stream *strm; + + if (gz == NULL || gz->write) + return 0; + if (gz->err) + return 0; + strm = &(gz->strm); + strm->next_out = (void *)buf; + strm->avail_out = len; + do { + got = fread(in, 1, 1, gz->file); + if (got == 0) + break; + strm->next_in = in; + strm->avail_in = 1; + ret = inflate(strm, Z_NO_FLUSH); + if (ret == Z_DATA_ERROR) { + gz->err = Z_DATA_ERROR; + gz->msg = strm->msg; + return 0; + } + if (ret == Z_STREAM_END) + inflateReset(strm); + } while (strm->avail_out); + return len - strm->avail_out; +} + +int gzclose OF((gzFile)); + +int gzclose(gz) + gzFile gz; +{ + z_stream *strm; + unsigned char out[BUFLEN]; + + if (gz == NULL) + return Z_STREAM_ERROR; + strm = &(gz->strm); + if (gz->write) { + strm->next_in = Z_NULL; + strm->avail_in = 0; + do { + strm->next_out = out; + strm->avail_out = BUFLEN; + (void)deflate(strm, Z_FINISH); + fwrite(out, 1, BUFLEN - strm->avail_out, gz->file); + } while (strm->avail_out == 0); + deflateEnd(strm); + } + else + inflateEnd(strm); + fclose(gz->file); + free(gz); + return Z_OK; +} + +const char *gzerror OF((gzFile, int *)); + +const char *gzerror(gz, err) + gzFile gz; + int *err; +{ + *err = gz->err; + return gz->msg; +} + +#endif + +char *prog; + +void error OF((const char *msg)); +void gz_compress OF((FILE *in, gzFile out)); +#ifdef USE_MMAP +int gz_compress_mmap OF((FILE *in, gzFile out)); +#endif +void gz_uncompress OF((gzFile in, FILE *out)); +void file_compress OF((char *file, char *mode)); +void file_uncompress OF((char *file)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Display error message and exit + */ +void error(msg) + const char *msg; +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + +/* =========================================================================== + * Compress input to output then close both files. + */ + +void gz_compress(in, out) + FILE *in; + gzFile out; +{ + local char buf[BUFLEN]; + int len; + int err; + +#ifdef USE_MMAP + /* Try first compressing with mmap. If mmap fails (minigzip used in a + * pipe), use the normal fread loop. + */ + if (gz_compress_mmap(in, out) == Z_OK) return; +#endif + for (;;) { + len = (int)fread(buf, 1, sizeof(buf), in); + if (ferror(in)) { + perror("fread"); + exit(1); + } + if (len == 0) break; + + if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); + } + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); +} + +#ifdef USE_MMAP /* MMAP version, Miguel Albrecht */ + +/* Try compressing the input file at once using mmap. Return Z_OK if + * if success, Z_ERRNO otherwise. + */ +int gz_compress_mmap(in, out) + FILE *in; + gzFile out; +{ + int len; + int err; + int ifd = fileno(in); + caddr_t buf; /* mmap'ed buffer for the entire input file */ + off_t buf_len; /* length of the input file */ + struct stat sb; + + /* Determine the size of the file, needed for mmap: */ + if (fstat(ifd, &sb) < 0) return Z_ERRNO; + buf_len = sb.st_size; + if (buf_len <= 0) return Z_ERRNO; + + /* Now do the actual mmap: */ + buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0); + if (buf == (caddr_t)(-1)) return Z_ERRNO; + + /* Compress the whole file at once: */ + len = gzwrite(out, (char *)buf, (unsigned)buf_len); + + if (len != (int)buf_len) error(gzerror(out, &err)); + + munmap(buf, buf_len); + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); + return Z_OK; +} +#endif /* USE_MMAP */ + +/* =========================================================================== + * Uncompress input to output then close both files. + */ +void gz_uncompress(in, out) + gzFile in; + FILE *out; +{ + local char buf[BUFLEN]; + int len; + int err; + + for (;;) { + len = gzread(in, buf, sizeof(buf)); + if (len < 0) error (gzerror(in, &err)); + if (len == 0) break; + + if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { + error("failed fwrite"); + } + } + if (fclose(out)) error("failed fclose"); + + if (gzclose(in) != Z_OK) error("failed gzclose"); +} + + +/* =========================================================================== + * Compress the given file: create a corresponding .gz file and remove the + * original. + */ +void file_compress(file, mode) + char *file; + char *mode; +{ + local char outfile[MAX_NAME_LEN]; + FILE *in; + gzFile out; + + if (strlen(file) + strlen(GZ_SUFFIX) >= sizeof(outfile)) { + fprintf(stderr, "%s: filename too long\n", prog); + exit(1); + } + +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(outfile, sizeof(outfile), "%s%s", file, GZ_SUFFIX); +#else + strcpy(outfile, file); + strcat(outfile, GZ_SUFFIX); +#endif + + in = fopen(file, "rb"); + if (in == NULL) { + perror(file); + exit(1); + } + out = gzopen(outfile, mode); + if (out == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); + exit(1); + } + gz_compress(in, out); + + unlink(file); +} + + +/* =========================================================================== + * Uncompress the given file and remove the original. + */ +void file_uncompress(file) + char *file; +{ + local char buf[MAX_NAME_LEN]; + char *infile, *outfile; + FILE *out; + gzFile in; + size_t len = strlen(file); + + if (len + strlen(GZ_SUFFIX) >= sizeof(buf)) { + fprintf(stderr, "%s: filename too long\n", prog); + exit(1); + } + +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(buf, sizeof(buf), "%s", file); +#else + strcpy(buf, file); +#endif + + if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { + infile = file; + outfile = buf; + outfile[len-3] = '\0'; + } else { + outfile = file; + infile = buf; +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(buf + len, sizeof(buf) - len, "%s", GZ_SUFFIX); +#else + strcat(infile, GZ_SUFFIX); +#endif + } + in = gzopen(infile, "rb"); + if (in == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); + exit(1); + } + out = fopen(outfile, "wb"); + if (out == NULL) { + perror(file); + exit(1); + } + + gz_uncompress(in, out); + + unlink(infile); +} + + +/* =========================================================================== + * Usage: minigzip [-c] [-d] [-f] [-h] [-r] [-1 to -9] [files...] + * -c : write to standard output + * -d : decompress + * -f : compress with Z_FILTERED + * -h : compress with Z_HUFFMAN_ONLY + * -r : compress with Z_RLE + * -1 to -9 : compression level + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + int copyout = 0; + int uncompr = 0; + gzFile file; + char *bname, outmode[20]; + +#if !defined(NO_snprintf) && !defined(NO_vsnprintf) + snprintf(outmode, sizeof(outmode), "%s", "wb6 "); +#else + strcpy(outmode, "wb6 "); +#endif + + prog = argv[0]; + bname = strrchr(argv[0], '/'); + if (bname) + bname++; + else + bname = argv[0]; + argc--, argv++; + + if (!strcmp(bname, "gunzip")) + uncompr = 1; + else if (!strcmp(bname, "zcat")) + copyout = uncompr = 1; + + while (argc > 0) { + if (strcmp(*argv, "-c") == 0) + copyout = 1; + else if (strcmp(*argv, "-d") == 0) + uncompr = 1; + else if (strcmp(*argv, "-f") == 0) + outmode[3] = 'f'; + else if (strcmp(*argv, "-h") == 0) + outmode[3] = 'h'; + else if (strcmp(*argv, "-r") == 0) + outmode[3] = 'R'; + else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' && + (*argv)[2] == 0) + outmode[2] = (*argv)[1]; + else + break; + argc--, argv++; + } + if (outmode[3] == ' ') + outmode[3] = 0; + if (argc == 0) { + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + if (uncompr) { + file = gzdopen(fileno(stdin), "rb"); + if (file == NULL) error("can't gzdopen stdin"); + gz_uncompress(file, stdout); + } else { + file = gzdopen(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + gz_compress(stdin, file); + } + } else { + if (copyout) { + SET_BINARY_MODE(stdout); + } + do { + if (uncompr) { + if (copyout) { + file = gzopen(*argv, "rb"); + if (file == NULL) + fprintf(stderr, "%s: can't gzopen %s\n", prog, *argv); + else + gz_uncompress(file, stdout); + } else { + file_uncompress(*argv); + } + } else { + if (copyout) { + FILE * in = fopen(*argv, "rb"); + + if (in == NULL) { + perror(*argv); + } else { + file = gzdopen(fileno(stdout), outmode); + if (file == NULL) error("can't gzdopen stdout"); + + gz_compress(in, file); + } + + } else { + file_compress(*argv, outmode); + } + } + } while (argv++, --argc); + } + return 0; +} diff --git a/test/zlib/zlib-1.2.8/treebuild.xml b/test/zlib/zlib-1.2.8/treebuild.xml new file mode 100644 index 000000000..38d29d75e --- /dev/null +++ b/test/zlib/zlib-1.2.8/treebuild.xml @@ -0,0 +1,116 @@ + + + + zip compression library + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/zlib/zlib-1.2.8/trees.c b/test/zlib/zlib-1.2.8/trees.c new file mode 100644 index 000000000..1fd7759ef --- /dev/null +++ b/test/zlib/zlib-1.2.8/trees.c @@ -0,0 +1,1226 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-2012 Jean-loup Gailly + * detect_data_type() function provided freely by Cosmin Truta, 2006 + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* @(#) $Id$ */ + +/* #define GEN_TREES_H */ + +#include "deflate.h" + +#ifdef DEBUG +# include +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local const int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local const uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ + +#if defined(GEN_TREES_H) || !defined(STDC) +/* non ANSI compilers may not accept trees.h */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +uch _dist_code[DIST_CODE_LEN]; +/* Distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +uch _length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +#else +# include "trees.h" +#endif /* GEN_TREES_H */ + +struct static_tree_desc_s { + const ct_data *static_tree; /* static tree or NULL */ + const intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, const ct_data *ltree, + const ct_data *dtree)); +local int detect_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifdef GEN_TREES_H +local void gen_trees_header OF((void)); +#endif + +#ifndef DEBUG +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (ush)value << s->bi_valid; + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= (ush)value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (ush)val << s->bi_valid;\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (ush)(value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. + */ +local void tr_static_init() +{ +#if defined(GEN_TREES_H) || !defined(STDC) + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* For some embedded targets, global variables are not initialized: */ +#ifdef NO_INIT_GLOBAL_POINTERS + static_l_desc.static_tree = static_ltree; + static_l_desc.extra_bits = extra_lbits; + static_d_desc.static_tree = static_dtree; + static_d_desc.extra_bits = extra_dbits; + static_bl_desc.extra_bits = extra_blbits; +#endif + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1< dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + _dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; + +# ifdef GEN_TREES_H + gen_trees_header(); +# endif +#endif /* defined(GEN_TREES_H) || !defined(STDC) */ +} + +/* =========================================================================== + * Genererate the file trees.h describing the static trees. + */ +#ifdef GEN_TREES_H +# ifndef DEBUG +# include +# endif + +# define SEPARATOR(i, last, width) \ + ((i) == (last)? "\n};\n\n" : \ + ((i) % (width) == (width)-1 ? ",\n" : ", ")) + +void gen_trees_header() +{ + FILE *header = fopen("trees.h", "w"); + int i; + + Assert (header != NULL, "Can't open trees.h"); + fprintf(header, + "/* header created automatically with -DGEN_TREES_H */\n\n"); + + fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); + for (i = 0; i < L_CODES+2; i++) { + fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, + static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); + } + + fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, + static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); + } + + fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); + for (i = 0; i < DIST_CODE_LEN; i++) { + fprintf(header, "%2u%s", _dist_code[i], + SEPARATOR(i, DIST_CODE_LEN-1, 20)); + } + + fprintf(header, + "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); + for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { + fprintf(header, "%2u%s", _length_code[i], + SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); + } + + fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); + for (i = 0; i < LENGTH_CODES; i++) { + fprintf(header, "%1u%s", base_length[i], + SEPARATOR(i, LENGTH_CODES-1, 20)); + } + + fprintf(header, "local const int base_dist[D_CODES] = {\n"); + for (i = 0; i < D_CODES; i++) { + fprintf(header, "%5u%s", base_dist[i], + SEPARATOR(i, D_CODES-1, 10)); + } + + fclose(header); +} +#endif /* GEN_TREES_H */ + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void ZLIB_INTERNAL _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->compressed_len = 0L; + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + const ct_data *stree = desc->stat_desc->static_tree; + const intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if ((unsigned) tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; + const ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? + s->depth[n] : s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ +#ifdef DEBUG + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; +#endif + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) + */ +void ZLIB_INTERNAL _tr_flush_bits(s) + deflate_state *s; +{ + bi_flush(s); +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + */ +void ZLIB_INTERNAL _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); +#ifdef DEBUG + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ +#endif + bi_flush(s); +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. + */ +void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int last; /* one if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is binary or text */ + if (s->strm->data_type == Z_UNKNOWN) + s->strm->data_type = detect_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute the block lengths in bytes. */ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, last); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+last, 3); + compress_block(s, (const ct_data *)static_ltree, + (const ct_data *)static_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->static_len; +#endif + } else { + send_bits(s, (DYN_TREES<<1)+last, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (const ct_data *)s->dyn_ltree, + (const ct_data *)s->dyn_dtree); +#ifdef DEBUG + s->compressed_len += 3 + s->opt_len; +#endif + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + /* The above check is made mod 2^32, for files larger than 512 MB + * and uLong implemented on 32 bits. + */ + init_block(s); + + if (last) { + bi_windup(s); +#ifdef DEBUG + s->compressed_len += 7; /* align on byte boundary */ +#endif + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*last)); +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int ZLIB_INTERNAL _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + +#ifdef TRUNCATE_BLOCK + /* Try to guess if it is profitable to stop the current block here */ + if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } +#endif + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + const ct_data *ltree; /* literal tree */ + const ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = _length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, + "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); +} + +/* =========================================================================== + * Check if the data type is TEXT or BINARY, using the following algorithm: + * - TEXT if the two conditions below are satisfied: + * a) There are no non-portable control characters belonging to the + * "black list" (0..6, 14..25, 28..31). + * b) There is at least one printable character belonging to the + * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). + * - BINARY otherwise. + * - The following partially-portable control characters form a + * "gray list" that is ignored in this detection algorithm: + * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). + * IN assertion: the fields Freq of dyn_ltree are set. + */ +local int detect_data_type(s) + deflate_state *s; +{ + /* black_mask is the bit mask of black-listed bytes + * set bits 0..6, 14..25, and 28..31 + * 0xf3ffc07f = binary 11110011111111111100000001111111 + */ + unsigned long black_mask = 0xf3ffc07fUL; + int n; + + /* Check for non-textual ("black-listed") bytes. */ + for (n = 0; n <= 31; n++, black_mask >>= 1) + if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) + return Z_BINARY; + + /* Check for textual ("white-listed") bytes. */ + if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 + || s->dyn_ltree[13].Freq != 0) + return Z_TEXT; + for (n = 32; n < LITERALS; n++) + if (s->dyn_ltree[n].Freq != 0) + return Z_TEXT; + + /* There are no "black-listed" or "white-listed" bytes: + * this stream either is empty or has tolerated ("gray-listed") bytes only. + */ + return Z_BINARY; +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/test/zlib/zlib-1.2.8/trees.h b/test/zlib/zlib-1.2.8/trees.h new file mode 100644 index 000000000..d35639d82 --- /dev/null +++ b/test/zlib/zlib-1.2.8/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { + 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, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 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, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 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, 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, 24, 24, 24, 24, 24, 24, 24, 24, 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, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/test/zlib/zlib-1.2.8/uncompr.c b/test/zlib/zlib-1.2.8/uncompr.c new file mode 100644 index 000000000..242e9493d --- /dev/null +++ b/test/zlib/zlib-1.2.8/uncompr.c @@ -0,0 +1,59 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-2003, 2010 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#define ZLIB_INTERNAL +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +int ZEXPORT uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (z_const Bytef *)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) + return Z_DATA_ERROR; + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/test/zlib/zlib-1.2.8/watcom/watcom_f.mak b/test/zlib/zlib-1.2.8/watcom/watcom_f.mak new file mode 100644 index 000000000..37f4d74c1 --- /dev/null +++ b/test/zlib/zlib-1.2.8/watcom/watcom_f.mak @@ -0,0 +1,43 @@ +# Makefile for zlib +# OpenWatcom flat model +# Last updated: 28-Dec-2005 + +# To use, do "wmake -f watcom_f.mak" + +C_SOURCE = adler32.c compress.c crc32.c deflate.c & + gzclose.c gzlib.c gzread.c gzwrite.c & + infback.c inffast.c inflate.c inftrees.c & + trees.c uncompr.c zutil.c + +OBJS = adler32.obj compress.obj crc32.obj deflate.obj & + gzclose.obj gzlib.obj gzread.obj gzwrite.obj & + infback.obj inffast.obj inflate.obj inftrees.obj & + trees.obj uncompr.obj zutil.obj + +CC = wcc386 +LINKER = wcl386 +CFLAGS = -zq -mf -3r -fp3 -s -bt=dos -oilrtfm -fr=nul -wx +ZLIB_LIB = zlib_f.lib + +.C.OBJ: + $(CC) $(CFLAGS) $[@ + +all: $(ZLIB_LIB) example.exe minigzip.exe + +$(ZLIB_LIB): $(OBJS) + wlib -b -c $(ZLIB_LIB) -+adler32.obj -+compress.obj -+crc32.obj + wlib -b -c $(ZLIB_LIB) -+gzclose.obj -+gzlib.obj -+gzread.obj -+gzwrite.obj + wlib -b -c $(ZLIB_LIB) -+deflate.obj -+infback.obj + wlib -b -c $(ZLIB_LIB) -+inffast.obj -+inflate.obj -+inftrees.obj + wlib -b -c $(ZLIB_LIB) -+trees.obj -+uncompr.obj -+zutil.obj + +example.exe: $(ZLIB_LIB) example.obj + $(LINKER) -ldos32a -fe=example.exe example.obj $(ZLIB_LIB) + +minigzip.exe: $(ZLIB_LIB) minigzip.obj + $(LINKER) -ldos32a -fe=minigzip.exe minigzip.obj $(ZLIB_LIB) + +clean: .SYMBOLIC + del *.obj + del $(ZLIB_LIB) + @echo Cleaning done diff --git a/test/zlib/zlib-1.2.8/watcom/watcom_l.mak b/test/zlib/zlib-1.2.8/watcom/watcom_l.mak new file mode 100644 index 000000000..193eed7b3 --- /dev/null +++ b/test/zlib/zlib-1.2.8/watcom/watcom_l.mak @@ -0,0 +1,43 @@ +# Makefile for zlib +# OpenWatcom large model +# Last updated: 28-Dec-2005 + +# To use, do "wmake -f watcom_l.mak" + +C_SOURCE = adler32.c compress.c crc32.c deflate.c & + gzclose.c gzlib.c gzread.c gzwrite.c & + infback.c inffast.c inflate.c inftrees.c & + trees.c uncompr.c zutil.c + +OBJS = adler32.obj compress.obj crc32.obj deflate.obj & + gzclose.obj gzlib.obj gzread.obj gzwrite.obj & + infback.obj inffast.obj inflate.obj inftrees.obj & + trees.obj uncompr.obj zutil.obj + +CC = wcc +LINKER = wcl +CFLAGS = -zq -ml -s -bt=dos -oilrtfm -fr=nul -wx +ZLIB_LIB = zlib_l.lib + +.C.OBJ: + $(CC) $(CFLAGS) $[@ + +all: $(ZLIB_LIB) example.exe minigzip.exe + +$(ZLIB_LIB): $(OBJS) + wlib -b -c $(ZLIB_LIB) -+adler32.obj -+compress.obj -+crc32.obj + wlib -b -c $(ZLIB_LIB) -+gzclose.obj -+gzlib.obj -+gzread.obj -+gzwrite.obj + wlib -b -c $(ZLIB_LIB) -+deflate.obj -+infback.obj + wlib -b -c $(ZLIB_LIB) -+inffast.obj -+inflate.obj -+inftrees.obj + wlib -b -c $(ZLIB_LIB) -+trees.obj -+uncompr.obj -+zutil.obj + +example.exe: $(ZLIB_LIB) example.obj + $(LINKER) -fe=example.exe example.obj $(ZLIB_LIB) + +minigzip.exe: $(ZLIB_LIB) minigzip.obj + $(LINKER) -fe=minigzip.exe minigzip.obj $(ZLIB_LIB) + +clean: .SYMBOLIC + del *.obj + del $(ZLIB_LIB) + @echo Cleaning done diff --git a/test/zlib/zlib-1.2.8/win32/DLL_FAQ.txt b/test/zlib/zlib-1.2.8/win32/DLL_FAQ.txt new file mode 100644 index 000000000..12c009018 --- /dev/null +++ b/test/zlib/zlib-1.2.8/win32/DLL_FAQ.txt @@ -0,0 +1,397 @@ + + Frequently Asked Questions about ZLIB1.DLL + + +This document describes the design, the rationale, and the usage +of the official DLL build of zlib, named ZLIB1.DLL. If you have +general questions about zlib, you should see the file "FAQ" found +in the zlib distribution, or at the following location: + http://www.gzip.org/zlib/zlib_faq.html + + + 1. What is ZLIB1.DLL, and how can I get it? + + - ZLIB1.DLL is the official build of zlib as a DLL. + (Please remark the character '1' in the name.) + + Pointers to a precompiled ZLIB1.DLL can be found in the zlib + web site at: + http://www.zlib.net/ + + Applications that link to ZLIB1.DLL can rely on the following + specification: + + * The exported symbols are exclusively defined in the source + files "zlib.h" and "zlib.def", found in an official zlib + source distribution. + * The symbols are exported by name, not by ordinal. + * The exported names are undecorated. + * The calling convention of functions is "C" (CDECL). + * The ZLIB1.DLL binary is linked to MSVCRT.DLL. + + The archive in which ZLIB1.DLL is bundled contains compiled + test programs that must run with a valid build of ZLIB1.DLL. + It is recommended to download the prebuilt DLL from the zlib + web site, instead of building it yourself, to avoid potential + incompatibilities that could be introduced by your compiler + and build settings. If you do build the DLL yourself, please + make sure that it complies with all the above requirements, + and it runs with the precompiled test programs, bundled with + the original ZLIB1.DLL distribution. + + If, for any reason, you need to build an incompatible DLL, + please use a different file name. + + + 2. Why did you change the name of the DLL to ZLIB1.DLL? + What happened to the old ZLIB.DLL? + + - The old ZLIB.DLL, built from zlib-1.1.4 or earlier, required + compilation settings that were incompatible to those used by + a static build. The DLL settings were supposed to be enabled + by defining the macro ZLIB_DLL, before including "zlib.h". + Incorrect handling of this macro was silently accepted at + build time, resulting in two major problems: + + * ZLIB_DLL was missing from the old makefile. When building + the DLL, not all people added it to the build options. In + consequence, incompatible incarnations of ZLIB.DLL started + to circulate around the net. + + * When switching from using the static library to using the + DLL, applications had to define the ZLIB_DLL macro and + to recompile all the sources that contained calls to zlib + functions. Failure to do so resulted in creating binaries + that were unable to run with the official ZLIB.DLL build. + + The only possible solution that we could foresee was to make + a binary-incompatible change in the DLL interface, in order to + remove the dependency on the ZLIB_DLL macro, and to release + the new DLL under a different name. + + We chose the name ZLIB1.DLL, where '1' indicates the major + zlib version number. We hope that we will not have to break + the binary compatibility again, at least not as long as the + zlib-1.x series will last. + + There is still a ZLIB_DLL macro, that can trigger a more + efficient build and use of the DLL, but compatibility no + longer dependents on it. + + + 3. Can I build ZLIB.DLL from the new zlib sources, and replace + an old ZLIB.DLL, that was built from zlib-1.1.4 or earlier? + + - In principle, you can do it by assigning calling convention + keywords to the macros ZEXPORT and ZEXPORTVA. In practice, + it depends on what you mean by "an old ZLIB.DLL", because the + old DLL exists in several mutually-incompatible versions. + You have to find out first what kind of calling convention is + being used in your particular ZLIB.DLL build, and to use the + same one in the new build. If you don't know what this is all + about, you might be better off if you would just leave the old + DLL intact. + + + 4. Can I compile my application using the new zlib interface, and + link it to an old ZLIB.DLL, that was built from zlib-1.1.4 or + earlier? + + - The official answer is "no"; the real answer depends again on + what kind of ZLIB.DLL you have. Even if you are lucky, this + course of action is unreliable. + + If you rebuild your application and you intend to use a newer + version of zlib (post- 1.1.4), it is strongly recommended to + link it to the new ZLIB1.DLL. + + + 5. Why are the zlib symbols exported by name, and not by ordinal? + + - Although exporting symbols by ordinal is a little faster, it + is risky. Any single glitch in the maintenance or use of the + DEF file that contains the ordinals can result in incompatible + builds and frustrating crashes. Simply put, the benefits of + exporting symbols by ordinal do not justify the risks. + + Technically, it should be possible to maintain ordinals in + the DEF file, and still export the symbols by name. Ordinals + exist in every DLL, and even if the dynamic linking performed + at the DLL startup is searching for names, ordinals serve as + hints, for a faster name lookup. However, if the DEF file + contains ordinals, the Microsoft linker automatically builds + an implib that will cause the executables linked to it to use + those ordinals, and not the names. It is interesting to + notice that the GNU linker for Win32 does not suffer from this + problem. + + It is possible to avoid the DEF file if the exported symbols + are accompanied by a "__declspec(dllexport)" attribute in the + source files. You can do this in zlib by predefining the + ZLIB_DLL macro. + + + 6. I see that the ZLIB1.DLL functions use the "C" (CDECL) calling + convention. Why not use the STDCALL convention? + STDCALL is the standard convention in Win32, and I need it in + my Visual Basic project! + + (For readability, we use CDECL to refer to the convention + triggered by the "__cdecl" keyword, STDCALL to refer to + the convention triggered by "__stdcall", and FASTCALL to + refer to the convention triggered by "__fastcall".) + + - Most of the native Windows API functions (without varargs) use + indeed the WINAPI convention (which translates to STDCALL in + Win32), but the standard C functions use CDECL. If a user + application is intrinsically tied to the Windows API (e.g. + it calls native Windows API functions such as CreateFile()), + sometimes it makes sense to decorate its own functions with + WINAPI. But if ANSI C or POSIX portability is a goal (e.g. + it calls standard C functions such as fopen()), it is not a + sound decision to request the inclusion of , or to + use non-ANSI constructs, for the sole purpose to make the user + functions STDCALL-able. + + The functionality offered by zlib is not in the category of + "Windows functionality", but is more like "C functionality". + + Technically, STDCALL is not bad; in fact, it is slightly + faster than CDECL, and it works with variable-argument + functions, just like CDECL. It is unfortunate that, in spite + of using STDCALL in the Windows API, it is not the default + convention used by the C compilers that run under Windows. + The roots of the problem reside deep inside the unsafety of + the K&R-style function prototypes, where the argument types + are not specified; but that is another story for another day. + + The remaining fact is that CDECL is the default convention. + Even if an explicit convention is hard-coded into the function + prototypes inside C headers, problems may appear. The + necessity to expose the convention in users' callbacks is one + of these problems. + + The calling convention issues are also important when using + zlib in other programming languages. Some of them, like Ada + (GNAT) and Fortran (GNU G77), have C bindings implemented + initially on Unix, and relying on the C calling convention. + On the other hand, the pre- .NET versions of Microsoft Visual + Basic require STDCALL, while Borland Delphi prefers, although + it does not require, FASTCALL. + + In fairness to all possible uses of zlib outside the C + programming language, we choose the default "C" convention. + Anyone interested in different bindings or conventions is + encouraged to maintain specialized projects. The "contrib/" + directory from the zlib distribution already holds a couple + of foreign bindings, such as Ada, C++, and Delphi. + + + 7. I need a DLL for my Visual Basic project. What can I do? + + - Define the ZLIB_WINAPI macro before including "zlib.h", when + building both the DLL and the user application (except that + you don't need to define anything when using the DLL in Visual + Basic). The ZLIB_WINAPI macro will switch on the WINAPI + (STDCALL) convention. The name of this DLL must be different + than the official ZLIB1.DLL. + + Gilles Vollant has contributed a build named ZLIBWAPI.DLL, + with the ZLIB_WINAPI macro turned on, and with the minizip + functionality built in. For more information, please read + the notes inside "contrib/vstudio/readme.txt", found in the + zlib distribution. + + + 8. I need to use zlib in my Microsoft .NET project. What can I + do? + + - Henrik Ravn has contributed a .NET wrapper around zlib. Look + into contrib/dotzlib/, inside the zlib distribution. + + + 9. If my application uses ZLIB1.DLL, should I link it to + MSVCRT.DLL? Why? + + - It is not required, but it is recommended to link your + application to MSVCRT.DLL, if it uses ZLIB1.DLL. + + The executables (.EXE, .DLL, etc.) that are involved in the + same process and are using the C run-time library (i.e. they + are calling standard C functions), must link to the same + library. There are several libraries in the Win32 system: + CRTDLL.DLL, MSVCRT.DLL, the static C libraries, etc. + Since ZLIB1.DLL is linked to MSVCRT.DLL, the executables that + depend on it should also be linked to MSVCRT.DLL. + + +10. Why are you saying that ZLIB1.DLL and my application should + be linked to the same C run-time (CRT) library? I linked my + application and my DLLs to different C libraries (e.g. my + application to a static library, and my DLLs to MSVCRT.DLL), + and everything works fine. + + - If a user library invokes only pure Win32 API (accessible via + and the related headers), its DLL build will work + in any context. But if this library invokes standard C API, + things get more complicated. + + There is a single Win32 library in a Win32 system. Every + function in this library resides in a single DLL module, that + is safe to call from anywhere. On the other hand, there are + multiple versions of the C library, and each of them has its + own separate internal state. Standalone executables and user + DLLs that call standard C functions must link to a C run-time + (CRT) library, be it static or shared (DLL). Intermixing + occurs when an executable (not necessarily standalone) and a + DLL are linked to different CRTs, and both are running in the + same process. + + Intermixing multiple CRTs is possible, as long as their + internal states are kept intact. The Microsoft Knowledge Base + articles KB94248 "HOWTO: Use the C Run-Time" and KB140584 + "HOWTO: Link with the Correct C Run-Time (CRT) Library" + mention the potential problems raised by intermixing. + + If intermixing works for you, it's because your application + and DLLs are avoiding the corruption of each of the CRTs' + internal states, maybe by careful design, or maybe by fortune. + + Also note that linking ZLIB1.DLL to non-Microsoft CRTs, such + as those provided by Borland, raises similar problems. + + +11. Why are you linking ZLIB1.DLL to MSVCRT.DLL? + + - MSVCRT.DLL exists on every Windows 95 with a new service pack + installed, or with Microsoft Internet Explorer 4 or later, and + on all other Windows 4.x or later (Windows 98, Windows NT 4, + or later). It is freely distributable; if not present in the + system, it can be downloaded from Microsoft or from other + software provider for free. + + The fact that MSVCRT.DLL does not exist on a virgin Windows 95 + is not so problematic. Windows 95 is scarcely found nowadays, + Microsoft ended its support a long time ago, and many recent + applications from various vendors, including Microsoft, do not + even run on it. Furthermore, no serious user should run + Windows 95 without a proper update installed. + + +12. Why are you not linking ZLIB1.DLL to + <> ? + + - We considered and abandoned the following alternatives: + + * Linking ZLIB1.DLL to a static C library (LIBC.LIB, or + LIBCMT.LIB) is not a good option. People are using the DLL + mainly to save disk space. If you are linking your program + to a static C library, you may as well consider linking zlib + in statically, too. + + * Linking ZLIB1.DLL to CRTDLL.DLL looks appealing, because + CRTDLL.DLL is present on every Win32 installation. + Unfortunately, it has a series of problems: it does not + work properly with Microsoft's C++ libraries, it does not + provide support for 64-bit file offsets, (and so on...), + and Microsoft discontinued its support a long time ago. + + * Linking ZLIB1.DLL to MSVCR70.DLL or MSVCR71.DLL, supplied + with the Microsoft .NET platform, and Visual C++ 7.0/7.1, + raises problems related to the status of ZLIB1.DLL as a + system component. According to the Microsoft Knowledge Base + article KB326922 "INFO: Redistribution of the Shared C + Runtime Component in Visual C++ .NET", MSVCR70.DLL and + MSVCR71.DLL are not supposed to function as system DLLs, + because they may clash with MSVCRT.DLL. Instead, the + application's installer is supposed to put these DLLs + (if needed) in the application's private directory. + If ZLIB1.DLL depends on a non-system runtime, it cannot + function as a redistributable system component. + + * Linking ZLIB1.DLL to non-Microsoft runtimes, such as + Borland's, or Cygwin's, raises problems related to the + reliable presence of these runtimes on Win32 systems. + It's easier to let the DLL build of zlib up to the people + who distribute these runtimes, and who may proceed as + explained in the answer to Question 14. + + +13. If ZLIB1.DLL cannot be linked to MSVCR70.DLL or MSVCR71.DLL, + how can I build/use ZLIB1.DLL in Microsoft Visual C++ 7.0 + (Visual Studio .NET) or newer? + + - Due to the problems explained in the Microsoft Knowledge Base + article KB326922 (see the previous answer), the C runtime that + comes with the VC7 environment is no longer considered a + system component. That is, it should not be assumed that this + runtime exists, or may be installed in a system directory. + Since ZLIB1.DLL is supposed to be a system component, it may + not depend on a non-system component. + + In order to link ZLIB1.DLL and your application to MSVCRT.DLL + in VC7, you need the library of Visual C++ 6.0 or older. If + you don't have this library at hand, it's probably best not to + use ZLIB1.DLL. + + We are hoping that, in the future, Microsoft will provide a + way to build applications linked to a proper system runtime, + from the Visual C++ environment. Until then, you have a + couple of alternatives, such as linking zlib in statically. + If your application requires dynamic linking, you may proceed + as explained in the answer to Question 14. + + +14. I need to link my own DLL build to a CRT different than + MSVCRT.DLL. What can I do? + + - Feel free to rebuild the DLL from the zlib sources, and link + it the way you want. You should, however, clearly state that + your build is unofficial. You should give it a different file + name, and/or install it in a private directory that can be + accessed by your application only, and is not visible to the + others (i.e. it's neither in the PATH, nor in the SYSTEM or + SYSTEM32 directories). Otherwise, your build may clash with + applications that link to the official build. + + For example, in Cygwin, zlib is linked to the Cygwin runtime + CYGWIN1.DLL, and it is distributed under the name CYGZ.DLL. + + +15. May I include additional pieces of code that I find useful, + link them in ZLIB1.DLL, and export them? + + - No. A legitimate build of ZLIB1.DLL must not include code + that does not originate from the official zlib source code. + But you can make your own private DLL build, under a different + file name, as suggested in the previous answer. + + For example, zlib is a part of the VCL library, distributed + with Borland Delphi and C++ Builder. The DLL build of VCL + is a redistributable file, named VCLxx.DLL. + + +16. May I remove some functionality out of ZLIB1.DLL, by enabling + macros like NO_GZCOMPRESS or NO_GZIP at compile time? + + - No. A legitimate build of ZLIB1.DLL must provide the complete + zlib functionality, as implemented in the official zlib source + code. But you can make your own private DLL build, under a + different file name, as suggested in the previous answer. + + +17. I made my own ZLIB1.DLL build. Can I test it for compliance? + + - We prefer that you download the official DLL from the zlib + web site. If you need something peculiar from this DLL, you + can send your suggestion to the zlib mailing list. + + However, in case you do rebuild the DLL yourself, you can run + it with the test programs found in the DLL distribution. + Running these test programs is not a guarantee of compliance, + but a failure can imply a detected problem. + +** + +This document is written and maintained by +Cosmin Truta diff --git a/test/zlib/zlib-1.2.8/win32/Makefile.bor b/test/zlib/zlib-1.2.8/win32/Makefile.bor new file mode 100644 index 000000000..d152bbb7f --- /dev/null +++ b/test/zlib/zlib-1.2.8/win32/Makefile.bor @@ -0,0 +1,110 @@ +# Makefile for zlib +# Borland C++ for Win32 +# +# Usage: +# make -f win32/Makefile.bor +# make -f win32/Makefile.bor LOCAL_ZLIB=-DASMV OBJA=match.obj OBJPA=+match.obj + +# ------------ Borland C++ ------------ + +# Optional nonstandard preprocessor flags (e.g. -DMAX_MEM_LEVEL=7) +# should be added to the environment via "set LOCAL_ZLIB=-DFOO" or +# added to the declaration of LOC here: +LOC = $(LOCAL_ZLIB) + +CC = bcc32 +AS = bcc32 +LD = bcc32 +AR = tlib +CFLAGS = -a -d -k- -O2 $(LOC) +ASFLAGS = $(LOC) +LDFLAGS = $(LOC) + + +# variables +ZLIB_LIB = zlib.lib + +OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj +OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj +#OBJA = +OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj +OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj +#OBJPA= + + +# targets +all: $(ZLIB_LIB) example.exe minigzip.exe + +.c.obj: + $(CC) -c $(CFLAGS) $< + +.asm.obj: + $(AS) -c $(ASFLAGS) $< + +adler32.obj: adler32.c zlib.h zconf.h + +compress.obj: compress.c zlib.h zconf.h + +crc32.obj: crc32.c zlib.h zconf.h crc32.h + +deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h + +gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h + +gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h + +gzread.obj: gzread.c zlib.h zconf.h gzguts.h + +gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h + +infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h + +inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \ + inffast.h inffixed.h + +inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h + +trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h + +uncompr.obj: uncompr.c zlib.h zconf.h + +zutil.obj: zutil.c zutil.h zlib.h zconf.h + +example.obj: test/example.c zlib.h zconf.h + +minigzip.obj: test/minigzip.c zlib.h zconf.h + + +# For the sake of the old Borland make, +# the command line is cut to fit in the MS-DOS 128 byte limit: +$(ZLIB_LIB): $(OBJ1) $(OBJ2) $(OBJA) + -del $(ZLIB_LIB) + $(AR) $(ZLIB_LIB) $(OBJP1) + $(AR) $(ZLIB_LIB) $(OBJP2) + $(AR) $(ZLIB_LIB) $(OBJPA) + + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +example.exe: example.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB) + +minigzip.exe: minigzip.obj $(ZLIB_LIB) + $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB) + + +# cleanup +clean: + -del $(ZLIB_LIB) + -del *.obj + -del *.exe + -del *.tds + -del zlib.bak + -del foo.gz diff --git a/test/zlib/zlib-1.2.8/win32/Makefile.gcc b/test/zlib/zlib-1.2.8/win32/Makefile.gcc new file mode 100644 index 000000000..6d1ded622 --- /dev/null +++ b/test/zlib/zlib-1.2.8/win32/Makefile.gcc @@ -0,0 +1,182 @@ +# Makefile for zlib, derived from Makefile.dj2. +# Modified for mingw32 by C. Spieler, 6/16/98. +# Updated for zlib 1.2.x by Christian Spieler and Cosmin Truta, Mar-2003. +# Last updated: Mar 2012. +# Tested under Cygwin and MinGW. + +# Copyright (C) 1995-2003 Jean-loup Gailly. +# For conditions of distribution and use, see copyright notice in zlib.h + +# To compile, or to compile and test, type from the top level zlib directory: +# +# make -fwin32/Makefile.gcc; make test testdll -fwin32/Makefile.gcc +# +# To use the asm code, type: +# cp contrib/asm?86/match.S ./match.S +# make LOC=-DASMV OBJA=match.o -fwin32/Makefile.gcc +# +# To install libz.a, zconf.h and zlib.h in the system directories, type: +# +# make install -fwin32/Makefile.gcc +# +# BINARY_PATH, INCLUDE_PATH and LIBRARY_PATH must be set. +# +# To install the shared lib, append SHARED_MODE=1 to the make command : +# +# make install -fwin32/Makefile.gcc SHARED_MODE=1 + +# Note: +# If the platform is *not* MinGW (e.g. it is Cygwin or UWIN), +# the DLL name should be changed from "zlib1.dll". + +STATICLIB = libz.a +SHAREDLIB = zlib1.dll +IMPLIB = libz.dll.a + +# +# Set to 1 if shared object needs to be installed +# +SHARED_MODE=0 + +#LOC = -DASMV +#LOC = -DDEBUG -g + +PREFIX = +CC = $(PREFIX)gcc +CFLAGS = $(LOC) -O3 -Wall + +AS = $(CC) +ASFLAGS = $(LOC) -Wall + +LD = $(CC) +LDFLAGS = $(LOC) + +AR = $(PREFIX)ar +ARFLAGS = rcs + +RC = $(PREFIX)windres +RCFLAGS = --define GCC_WINDRES + +STRIP = $(PREFIX)strip + +CP = cp -fp +# If GNU install is available, replace $(CP) with install. +INSTALL = $(CP) +RM = rm -f + +prefix ?= /usr/local +exec_prefix = $(prefix) + +OBJS = adler32.o compress.o crc32.o deflate.o gzclose.o gzlib.o gzread.o \ + gzwrite.o infback.o inffast.o inflate.o inftrees.o trees.o uncompr.o zutil.o +OBJA = + +all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB) example.exe minigzip.exe example_d.exe minigzip_d.exe + +test: example.exe minigzip.exe + ./example + echo hello world | ./minigzip | ./minigzip -d + +testdll: example_d.exe minigzip_d.exe + ./example_d + echo hello world | ./minigzip_d | ./minigzip_d -d + +.c.o: + $(CC) $(CFLAGS) -c -o $@ $< + +.S.o: + $(AS) $(ASFLAGS) -c -o $@ $< + +$(STATICLIB): $(OBJS) $(OBJA) + $(AR) $(ARFLAGS) $@ $(OBJS) $(OBJA) + +$(IMPLIB): $(SHAREDLIB) + +$(SHAREDLIB): win32/zlib.def $(OBJS) $(OBJA) zlibrc.o + $(CC) -shared -Wl,--out-implib,$(IMPLIB) $(LDFLAGS) \ + -o $@ win32/zlib.def $(OBJS) $(OBJA) zlibrc.o + $(STRIP) $@ + +example.exe: example.o $(STATICLIB) + $(LD) $(LDFLAGS) -o $@ example.o $(STATICLIB) + $(STRIP) $@ + +minigzip.exe: minigzip.o $(STATICLIB) + $(LD) $(LDFLAGS) -o $@ minigzip.o $(STATICLIB) + $(STRIP) $@ + +example_d.exe: example.o $(IMPLIB) + $(LD) $(LDFLAGS) -o $@ example.o $(IMPLIB) + $(STRIP) $@ + +minigzip_d.exe: minigzip.o $(IMPLIB) + $(LD) $(LDFLAGS) -o $@ minigzip.o $(IMPLIB) + $(STRIP) $@ + +example.o: test/example.c zlib.h zconf.h + $(CC) $(CFLAGS) -I. -c -o $@ test/example.c + +minigzip.o: test/minigzip.c zlib.h zconf.h + $(CC) $(CFLAGS) -I. -c -o $@ test/minigzip.c + +zlibrc.o: win32/zlib1.rc + $(RC) $(RCFLAGS) -o $@ win32/zlib1.rc + +.PHONY: install uninstall clean + +install: zlib.h zconf.h $(STATICLIB) $(IMPLIB) + @if test -z "$(DESTDIR)$(INCLUDE_PATH)" -o -z "$(DESTDIR)$(LIBRARY_PATH)" -o -z "$(DESTDIR)$(BINARY_PATH)"; then \ + echo INCLUDE_PATH, LIBRARY_PATH, and BINARY_PATH must be specified; \ + exit 1; \ + fi + -@mkdir -p '$(DESTDIR)$(INCLUDE_PATH)' + -@mkdir -p '$(DESTDIR)$(LIBRARY_PATH)' '$(DESTDIR)$(LIBRARY_PATH)'/pkgconfig + -if [ "$(SHARED_MODE)" = "1" ]; then \ + mkdir -p '$(DESTDIR)$(BINARY_PATH)'; \ + $(INSTALL) $(SHAREDLIB) '$(DESTDIR)$(BINARY_PATH)'; \ + $(INSTALL) $(IMPLIB) '$(DESTDIR)$(LIBRARY_PATH)'; \ + fi + -$(INSTALL) zlib.h '$(DESTDIR)$(INCLUDE_PATH)' + -$(INSTALL) zconf.h '$(DESTDIR)$(INCLUDE_PATH)' + -$(INSTALL) $(STATICLIB) '$(DESTDIR)$(LIBRARY_PATH)' + sed \ + -e 's|@prefix@|${prefix}|g' \ + -e 's|@exec_prefix@|${exec_prefix}|g' \ + -e 's|@libdir@|$(LIBRARY_PATH)|g' \ + -e 's|@sharedlibdir@|$(LIBRARY_PATH)|g' \ + -e 's|@includedir@|$(INCLUDE_PATH)|g' \ + -e 's|@VERSION@|'`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' zlib.h`'|g' \ + zlib.pc.in > '$(DESTDIR)$(LIBRARY_PATH)'/pkgconfig/zlib.pc + +uninstall: + -if [ "$(SHARED_MODE)" = "1" ]; then \ + $(RM) '$(DESTDIR)$(BINARY_PATH)'/$(SHAREDLIB); \ + $(RM) '$(DESTDIR)$(LIBRARY_PATH)'/$(IMPLIB); \ + fi + -$(RM) '$(DESTDIR)$(INCLUDE_PATH)'/zlib.h + -$(RM) '$(DESTDIR)$(INCLUDE_PATH)'/zconf.h + -$(RM) '$(DESTDIR)$(LIBRARY_PATH)'/$(STATICLIB) + +clean: + -$(RM) $(STATICLIB) + -$(RM) $(SHAREDLIB) + -$(RM) $(IMPLIB) + -$(RM) *.o + -$(RM) *.exe + -$(RM) foo.gz + +adler32.o: zlib.h zconf.h +compress.o: zlib.h zconf.h +crc32.o: crc32.h zlib.h zconf.h +deflate.o: deflate.h zutil.h zlib.h zconf.h +gzclose.o: zlib.h zconf.h gzguts.h +gzlib.o: zlib.h zconf.h gzguts.h +gzread.o: zlib.h zconf.h gzguts.h +gzwrite.o: zlib.h zconf.h gzguts.h +inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h +inftrees.o: zutil.h zlib.h zconf.h inftrees.h +trees.o: deflate.h zutil.h zlib.h zconf.h trees.h +uncompr.o: zlib.h zconf.h +zutil.o: zutil.h zlib.h zconf.h diff --git a/test/zlib/zlib-1.2.8/win32/Makefile.msc b/test/zlib/zlib-1.2.8/win32/Makefile.msc new file mode 100644 index 000000000..67b773171 --- /dev/null +++ b/test/zlib/zlib-1.2.8/win32/Makefile.msc @@ -0,0 +1,163 @@ +# Makefile for zlib using Microsoft (Visual) C +# zlib is copyright (C) 1995-2006 Jean-loup Gailly and Mark Adler +# +# Usage: +# nmake -f win32/Makefile.msc (standard build) +# nmake -f win32/Makefile.msc LOC=-DFOO (nonstandard build) +# nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" \ +# OBJA="inffas32.obj match686.obj" (use ASM code, x86) +# nmake -f win32/Makefile.msc AS=ml64 LOC="-DASMV -DASMINF -I." \ +# OBJA="inffasx64.obj gvmat64.obj inffas8664.obj" (use ASM code, x64) + +# The toplevel directory of the source tree. +# +TOP = . + +# optional build flags +LOC = + +# variables +STATICLIB = zlib.lib +SHAREDLIB = zlib1.dll +IMPLIB = zdll.lib + +CC = cl +AS = ml +LD = link +AR = lib +RC = rc +CFLAGS = -nologo -MD -W3 -O2 -Oy- -Zi -Fd"zlib" $(LOC) +WFLAGS = -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE +ASFLAGS = -coff -Zi $(LOC) +LDFLAGS = -nologo -debug -incremental:no -opt:ref +ARFLAGS = -nologo +RCFLAGS = /dWIN32 /r + +OBJS = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj \ + gzwrite.obj infback.obj inflate.obj inftrees.obj inffast.obj trees.obj uncompr.obj zutil.obj +OBJA = + + +# targets +all: $(STATICLIB) $(SHAREDLIB) $(IMPLIB) \ + example.exe minigzip.exe example_d.exe minigzip_d.exe + +$(STATICLIB): $(OBJS) $(OBJA) + $(AR) $(ARFLAGS) -out:$@ $(OBJS) $(OBJA) + +$(IMPLIB): $(SHAREDLIB) + +$(SHAREDLIB): $(TOP)/win32/zlib.def $(OBJS) $(OBJA) zlib1.res + $(LD) $(LDFLAGS) -def:$(TOP)/win32/zlib.def -dll -implib:$(IMPLIB) \ + -out:$@ -base:0x5A4C0000 $(OBJS) $(OBJA) zlib1.res + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;2 + +example.exe: example.obj $(STATICLIB) + $(LD) $(LDFLAGS) example.obj $(STATICLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +minigzip.exe: minigzip.obj $(STATICLIB) + $(LD) $(LDFLAGS) minigzip.obj $(STATICLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +example_d.exe: example.obj $(IMPLIB) + $(LD) $(LDFLAGS) -out:$@ example.obj $(IMPLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +minigzip_d.exe: minigzip.obj $(IMPLIB) + $(LD) $(LDFLAGS) -out:$@ minigzip.obj $(IMPLIB) + if exist $@.manifest \ + mt -nologo -manifest $@.manifest -outputresource:$@;1 + +{$(TOP)}.c.obj: + $(CC) -c $(WFLAGS) $(CFLAGS) $< + +{$(TOP)/test}.c.obj: + $(CC) -c -I$(TOP) $(WFLAGS) $(CFLAGS) $< + +{$(TOP)/contrib/masmx64}.c.obj: + $(CC) -c $(WFLAGS) $(CFLAGS) $< + +{$(TOP)/contrib/masmx64}.asm.obj: + $(AS) -c $(ASFLAGS) $< + +{$(TOP)/contrib/masmx86}.asm.obj: + $(AS) -c $(ASFLAGS) $< + +adler32.obj: $(TOP)/adler32.c $(TOP)/zlib.h $(TOP)/zconf.h + +compress.obj: $(TOP)/compress.c $(TOP)/zlib.h $(TOP)/zconf.h + +crc32.obj: $(TOP)/crc32.c $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/crc32.h + +deflate.obj: $(TOP)/deflate.c $(TOP)/deflate.h $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h + +gzclose.obj: $(TOP)/gzclose.c $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/gzguts.h + +gzlib.obj: $(TOP)/gzlib.c $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/gzguts.h + +gzread.obj: $(TOP)/gzread.c $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/gzguts.h + +gzwrite.obj: $(TOP)/gzwrite.c $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/gzguts.h + +infback.obj: $(TOP)/infback.c $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/inftrees.h $(TOP)/inflate.h \ + $(TOP)/inffast.h $(TOP)/inffixed.h + +inffast.obj: $(TOP)/inffast.c $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/inftrees.h $(TOP)/inflate.h \ + $(TOP)/inffast.h + +inflate.obj: $(TOP)/inflate.c $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/inftrees.h $(TOP)/inflate.h \ + $(TOP)/inffast.h $(TOP)/inffixed.h + +inftrees.obj: $(TOP)/inftrees.c $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/inftrees.h + +trees.obj: $(TOP)/trees.c $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h $(TOP)/deflate.h $(TOP)/trees.h + +uncompr.obj: $(TOP)/uncompr.c $(TOP)/zlib.h $(TOP)/zconf.h + +zutil.obj: $(TOP)/zutil.c $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h + +gvmat64.obj: $(TOP)/contrib\masmx64\gvmat64.asm + +inffasx64.obj: $(TOP)/contrib\masmx64\inffasx64.asm + +inffas8664.obj: $(TOP)/contrib\masmx64\inffas8664.c $(TOP)/zutil.h $(TOP)/zlib.h $(TOP)/zconf.h \ + $(TOP)/inftrees.h $(TOP)/inflate.h $(TOP)/inffast.h + +inffas32.obj: $(TOP)/contrib\masmx86\inffas32.asm + +match686.obj: $(TOP)/contrib\masmx86\match686.asm + +example.obj: $(TOP)/test/example.c $(TOP)/zlib.h $(TOP)/zconf.h + +minigzip.obj: $(TOP)/test/minigzip.c $(TOP)/zlib.h $(TOP)/zconf.h + +zlib1.res: $(TOP)/win32/zlib1.rc + $(RC) $(RCFLAGS) /fo$@ $(TOP)/win32/zlib1.rc + +# testing +test: example.exe minigzip.exe + example + echo hello world | minigzip | minigzip -d + +testdll: example_d.exe minigzip_d.exe + example_d + echo hello world | minigzip_d | minigzip_d -d + + +# cleanup +clean: + -del $(STATICLIB) + -del $(SHAREDLIB) + -del $(IMPLIB) + -del *.obj + -del *.res + -del *.exp + -del *.exe + -del *.pdb + -del *.manifest + -del foo.gz diff --git a/test/zlib/zlib-1.2.8/win32/README-WIN32.txt b/test/zlib/zlib-1.2.8/win32/README-WIN32.txt new file mode 100644 index 000000000..3d77d521e --- /dev/null +++ b/test/zlib/zlib-1.2.8/win32/README-WIN32.txt @@ -0,0 +1,103 @@ +ZLIB DATA COMPRESSION LIBRARY + +zlib 1.2.8 is a general purpose data compression library. All the code is +thread safe. The data format used by the zlib library is described by RFCs +(Request for Comments) 1950 to 1952 in the files +http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) +and rfc1952.txt (gzip format). + +All functions of the compression library are documented in the file zlib.h +(volunteer to write man pages welcome, contact zlib@gzip.org). Two compiled +examples are distributed in this package, example and minigzip. The example_d +and minigzip_d flavors validate that the zlib1.dll file is working correctly. + +Questions about zlib should be sent to . The zlib home page +is http://zlib.net/ . Before reporting a problem, please check this site to +verify that you have the latest version of zlib; otherwise get the latest +version and check whether the problem still exists or not. + +PLEASE read DLL_FAQ.txt, and the the zlib FAQ http://zlib.net/zlib_faq.html +before asking for help. + + +Manifest: + +The package zlib-1.2.8-win32-x86.zip will contain the following files: + + README-WIN32.txt This document + ChangeLog Changes since previous zlib packages + DLL_FAQ.txt Frequently asked questions about zlib1.dll + zlib.3.pdf Documentation of this library in Adobe Acrobat format + + example.exe A statically-bound example (using zlib.lib, not the dll) + example.pdb Symbolic information for debugging example.exe + + example_d.exe A zlib1.dll bound example (using zdll.lib) + example_d.pdb Symbolic information for debugging example_d.exe + + minigzip.exe A statically-bound test program (using zlib.lib, not the dll) + minigzip.pdb Symbolic information for debugging minigzip.exe + + minigzip_d.exe A zlib1.dll bound test program (using zdll.lib) + minigzip_d.pdb Symbolic information for debugging minigzip_d.exe + + zlib.h Install these files into the compilers' INCLUDE path to + zconf.h compile programs which use zlib.lib or zdll.lib + + zdll.lib Install these files into the compilers' LIB path if linking + zdll.exp a compiled program to the zlib1.dll binary + + zlib.lib Install these files into the compilers' LIB path to link zlib + zlib.pdb into compiled programs, without zlib1.dll runtime dependency + (zlib.pdb provides debugging info to the compile time linker) + + zlib1.dll Install this binary shared library into the system PATH, or + the program's runtime directory (where the .exe resides) + zlib1.pdb Install in the same directory as zlib1.dll, in order to debug + an application crash using WinDbg or similar tools. + +All .pdb files above are entirely optional, but are very useful to a developer +attempting to diagnose program misbehavior or a crash. Many additional +important files for developers can be found in the zlib127.zip source package +available from http://zlib.net/ - review that package's README file for details. + + +Acknowledgments: + +The deflate format used by zlib was defined by Phil Katz. The deflate and +zlib specifications were written by L. Peter Deutsch. Thanks to all the +people who reported problems and suggested various improvements in zlib; they +are too numerous to cite here. + + +Copyright notice: + + (C) 1995-2012 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. diff --git a/test/zlib/zlib-1.2.8/win32/VisualC.txt b/test/zlib/zlib-1.2.8/win32/VisualC.txt new file mode 100644 index 000000000..579a5fc9e --- /dev/null +++ b/test/zlib/zlib-1.2.8/win32/VisualC.txt @@ -0,0 +1,3 @@ + +To build zlib using the Microsoft Visual C++ environment, +use the appropriate project from the projects/ directory. diff --git a/test/zlib/zlib-1.2.8/win32/zlib.def b/test/zlib/zlib-1.2.8/win32/zlib.def new file mode 100644 index 000000000..face65518 --- /dev/null +++ b/test/zlib/zlib-1.2.8/win32/zlib.def @@ -0,0 +1,86 @@ +; zlib data compression library +EXPORTS +; basic functions + zlibVersion + deflate + deflateEnd + inflate + inflateEnd +; advanced functions + deflateSetDictionary + deflateCopy + deflateReset + deflateParams + deflateTune + deflateBound + deflatePending + deflatePrime + deflateSetHeader + inflateSetDictionary + inflateGetDictionary + inflateSync + inflateCopy + inflateReset + inflateReset2 + inflatePrime + inflateMark + inflateGetHeader + inflateBack + inflateBackEnd + zlibCompileFlags +; utility functions + compress + compress2 + compressBound + uncompress + gzopen + gzdopen + gzbuffer + gzsetparams + gzread + gzwrite + gzprintf + gzvprintf + gzputs + gzgets + gzputc + gzgetc + gzungetc + gzflush + gzseek + gzrewind + gztell + gzoffset + gzeof + gzdirect + gzclose + gzclose_r + gzclose_w + gzerror + gzclearerr +; large file functions + gzopen64 + gzseek64 + gztell64 + gzoffset64 + adler32_combine64 + crc32_combine64 +; checksum functions + adler32 + crc32 + adler32_combine + crc32_combine +; various hacks, don't look :) + deflateInit_ + deflateInit2_ + inflateInit_ + inflateInit2_ + inflateBackInit_ + gzgetc_ + zError + inflateSyncPoint + get_crc_table + inflateUndermine + inflateResetKeep + deflateResetKeep + gzopen_w diff --git a/test/zlib/zlib-1.2.8/win32/zlib1.rc b/test/zlib/zlib-1.2.8/win32/zlib1.rc new file mode 100644 index 000000000..5c0feed1b --- /dev/null +++ b/test/zlib/zlib-1.2.8/win32/zlib1.rc @@ -0,0 +1,40 @@ +#include +#include "../zlib.h" + +#ifdef GCC_WINDRES +VS_VERSION_INFO VERSIONINFO +#else +VS_VERSION_INFO VERSIONINFO MOVEABLE IMPURE LOADONCALL DISCARDABLE +#endif + FILEVERSION ZLIB_VER_MAJOR,ZLIB_VER_MINOR,ZLIB_VER_REVISION,0 + PRODUCTVERSION ZLIB_VER_MAJOR,ZLIB_VER_MINOR,ZLIB_VER_REVISION,0 + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS 1 +#else + FILEFLAGS 0 +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_DLL + FILESUBTYPE 0 // not used +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904E4" + //language ID = U.S. English, char set = Windows, Multilingual + BEGIN + VALUE "FileDescription", "zlib data compression library\0" + VALUE "FileVersion", ZLIB_VERSION "\0" + VALUE "InternalName", "zlib1.dll\0" + VALUE "LegalCopyright", "(C) 1995-2013 Jean-loup Gailly & Mark Adler\0" + VALUE "OriginalFilename", "zlib1.dll\0" + VALUE "ProductName", "zlib\0" + VALUE "ProductVersion", ZLIB_VERSION "\0" + VALUE "Comments", "For more information visit http://www.zlib.net/\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409, 1252 + END +END diff --git a/test/zlib/zlib-1.2.8/zconf.h b/test/zlib/zlib-1.2.8/zconf.h new file mode 100644 index 000000000..9987a7755 --- /dev/null +++ b/test/zlib/zlib-1.2.8/zconf.h @@ -0,0 +1,511 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2013 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzvprintf z_gzvprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateGetDictionary z_inflateGetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateResetKeep z_inflateResetKeep +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/test/zlib/zlib-1.2.8/zconf.h.cmakein b/test/zlib/zlib-1.2.8/zconf.h.cmakein new file mode 100644 index 000000000..043019cda --- /dev/null +++ b/test/zlib/zlib-1.2.8/zconf.h.cmakein @@ -0,0 +1,513 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2013 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H +#cmakedefine Z_PREFIX +#cmakedefine Z_HAVE_UNISTD_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzvprintf z_gzvprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateGetDictionary z_inflateGetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateResetKeep z_inflateResetKeep +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/test/zlib/zlib-1.2.8/zconf.h.in b/test/zlib/zlib-1.2.8/zconf.h.in new file mode 100644 index 000000000..9987a7755 --- /dev/null +++ b/test/zlib/zlib-1.2.8/zconf.h.in @@ -0,0 +1,511 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-2013 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#ifndef ZCONF_H +#define ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". + */ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define deflate z_deflate +# define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending +# define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzvprintf z_gzvprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetHeader z_inflateGetHeader +# define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateSetDictionary z_inflateSetDictionary +# define inflateGetDictionary z_inflateGetDictionary +# define inflateSync z_inflateSync +# define inflateSyncPoint z_inflateSyncPoint +# define inflateUndermine z_inflateUndermine +# define inflateResetKeep z_inflateResetKeep +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# endif +# define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion + +/* all zlib typedefs in zlib.h and zconf.h */ +# define Byte z_Byte +# define Bytef z_Bytef +# define alloc_func z_alloc_func +# define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func +# define intf z_intf +# define out_func z_out_func +# define uInt z_uInt +# define uIntf z_uIntf +# define uLong z_uLong +# define uLongf z_uLongf +# define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + +#endif + +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif +#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) +# define OS2 +#endif +#if defined(_WINDOWS) && !defined(WINDOWS) +# define WINDOWS +#endif +#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) +# ifndef WIN32 +# define WIN32 +# endif +#endif +#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) +# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) +# ifndef SYS16BIT +# define SYS16BIT +# endif +# endif +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#ifdef SYS16BIT +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#ifdef __STDC_VERSION__ +# ifndef STDC +# define STDC +# endif +# if __STDC_VERSION__ >= 199901L +# ifndef STDC99 +# define STDC99 +# endif +# endif +#endif +#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) +# define STDC +#endif +#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) +# define STDC +#endif +#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) +# define STDC +#endif +#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) +# define STDC +#endif + +#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const /* note: need a more gentle solution here */ +# endif +#endif + +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#ifdef SYS16BIT +# if defined(M_I86SM) || defined(M_I86MM) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR _far +# else +# define FAR far +# endif +# endif +# if (defined(__SMALL__) || defined(__MEDIUM__)) + /* Turbo C small or medium model */ +# define SMALL_MEDIUM +# ifdef __BORLANDC__ +# define FAR _far +# else +# define FAR far +# endif +# endif +#endif + +#if defined(WINDOWS) || defined(WIN32) + /* If building or using zlib as a DLL, define ZLIB_DLL. + * This is not mandatory, but it offers a little performance increase. + */ +# ifdef ZLIB_DLL +# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) +# ifdef ZLIB_INTERNAL +# define ZEXTERN extern __declspec(dllexport) +# else +# define ZEXTERN extern __declspec(dllimport) +# endif +# endif +# endif /* ZLIB_DLL */ + /* If building or using zlib with the WINAPI/WINAPIV calling convention, + * define ZLIB_WINAPI. + * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. + */ +# ifdef ZLIB_WINAPI +# ifdef FAR +# undef FAR +# endif +# include + /* No need for _export, use ZLIB.DEF instead. */ + /* For complete Windows compatibility, use WINAPI, not __stdcall. */ +# define ZEXPORT WINAPI +# ifdef WIN32 +# define ZEXPORTVA WINAPIV +# else +# define ZEXPORTVA FAR CDECL +# endif +# endif +#endif + +#if defined (__BEOS__) +# ifdef ZLIB_DLL +# ifdef ZLIB_INTERNAL +# define ZEXPORT __declspec(dllexport) +# define ZEXPORTVA __declspec(dllexport) +# else +# define ZEXPORT __declspec(dllimport) +# define ZEXPORTVA __declspec(dllimport) +# endif +# endif +#endif + +#ifndef ZEXTERN +# define ZEXTERN extern +#endif +#ifndef ZEXPORT +# define ZEXPORT +#endif +#ifndef ZEXPORTVA +# define ZEXPORTVA +#endif + +#ifndef FAR +# define FAR +#endif + +#if !defined(__MACTYPES__) +typedef unsigned char Byte; /* 8 bits */ +#endif +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#ifdef SMALL_MEDIUM + /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void const *voidpc; + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte const *voidpc; + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short +# endif +#endif + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#ifndef z_off_t +# define z_off_t long +#endif + +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t +# endif +#endif + +/* MVS linker does not support external names larger than 8 bytes */ +#if defined(__MVS__) + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") +#endif + +#endif /* ZCONF_H */ diff --git a/test/zlib/zlib-1.2.8/zlib.3 b/test/zlib/zlib-1.2.8/zlib.3 new file mode 100644 index 000000000..0160e62b6 --- /dev/null +++ b/test/zlib/zlib-1.2.8/zlib.3 @@ -0,0 +1,151 @@ +.TH ZLIB 3 "28 Apr 2013" +.SH NAME +zlib \- compression/decompression library +.SH SYNOPSIS +[see +.I zlib.h +for full description] +.SH DESCRIPTION +The +.I zlib +library is a general purpose data compression library. +The code is thread safe, assuming that the standard library functions +used are thread safe, such as memory allocation routines. +It provides in-memory compression and decompression functions, +including integrity checks of the uncompressed data. +This version of the library supports only one compression method (deflation) +but other algorithms may be added later +with the same stream interface. +.LP +Compression can be done in a single step if the buffers are large enough +or can be done by repeated calls of the compression function. +In the latter case, +the application must provide more input and/or consume the output +(providing more output space) before each call. +.LP +The library also supports reading and writing files in +.IR gzip (1) +(.gz) format +with an interface similar to that of stdio. +.LP +The library does not install any signal handler. +The decoder checks the consistency of the compressed data, +so the library should never crash even in the case of corrupted input. +.LP +All functions of the compression library are documented in the file +.IR zlib.h . +The distribution source includes examples of use of the library +in the files +.I test/example.c +and +.IR test/minigzip.c, +as well as other examples in the +.IR examples/ +directory. +.LP +Changes to this version are documented in the file +.I ChangeLog +that accompanies the source. +.LP +.I zlib +is available in Java using the java.util.zip package: +.IP +http://java.sun.com/developer/technicalArticles/Programming/compression/ +.LP +A Perl interface to +.IR zlib , +written by Paul Marquess (pmqs@cpan.org), +is available at CPAN (Comprehensive Perl Archive Network) sites, +including: +.IP +http://search.cpan.org/~pmqs/IO-Compress-Zlib/ +.LP +A Python interface to +.IR zlib , +written by A.M. Kuchling (amk@magnet.com), +is available in Python 1.5 and later versions: +.IP +http://docs.python.org/library/zlib.html +.LP +.I zlib +is built into +.IR tcl: +.IP +http://wiki.tcl.tk/4610 +.LP +An experimental package to read and write files in .zip format, +written on top of +.I zlib +by Gilles Vollant (info@winimage.com), +is available at: +.IP +http://www.winimage.com/zLibDll/minizip.html +and also in the +.I contrib/minizip +directory of the main +.I zlib +source distribution. +.SH "SEE ALSO" +The +.I zlib +web site can be found at: +.IP +http://zlib.net/ +.LP +The data format used by the zlib library is described by RFC +(Request for Comments) 1950 to 1952 in the files: +.IP +http://tools.ietf.org/html/rfc1950 (for the zlib header and trailer format) +.br +http://tools.ietf.org/html/rfc1951 (for the deflate compressed data format) +.br +http://tools.ietf.org/html/rfc1952 (for the gzip header and trailer format) +.LP +Mark Nelson wrote an article about +.I zlib +for the Jan. 1997 issue of Dr. Dobb's Journal; +a copy of the article is available at: +.IP +http://marknelson.us/1997/01/01/zlib-engine/ +.SH "REPORTING PROBLEMS" +Before reporting a problem, +please check the +.I zlib +web site to verify that you have the latest version of +.IR zlib ; +otherwise, +obtain the latest version and see if the problem still exists. +Please read the +.I zlib +FAQ at: +.IP +http://zlib.net/zlib_faq.html +.LP +before asking for help. +Send questions and/or comments to zlib@gzip.org, +or (for the Windows DLL version) to Gilles Vollant (info@winimage.com). +.SH AUTHORS +Version 1.2.8 +Copyright (C) 1995-2013 Jean-loup Gailly (jloup@gzip.org) +and Mark Adler (madler@alumni.caltech.edu). +.LP +This software is provided "as-is," +without any express or implied warranty. +In no event will the authors be held liable for any damages +arising from the use of this software. +See the distribution directory with respect to requirements +governing redistribution. +The deflate format used by +.I zlib +was defined by Phil Katz. +The deflate and +.I zlib +specifications were written by L. Peter Deutsch. +Thanks to all the people who reported problems and suggested various +improvements in +.IR zlib ; +who are too numerous to cite here. +.LP +UNIX manual page by R. P. C. Rodgers, +U.S. National Library of Medicine (rodgers@nlm.nih.gov). +.\" end of man page diff --git a/test/zlib/zlib-1.2.8/zlib.3.pdf b/test/zlib/zlib-1.2.8/zlib.3.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a346b5d7e24834806b0871b209637c728fb36d60 GIT binary patch literal 8734 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 literal 0 HcmV?d00001 diff --git a/test/zlib/zlib-1.2.8/zlib.h b/test/zlib/zlib-1.2.8/zlib.h new file mode 100644 index 000000000..3e0c7672a --- /dev/null +++ b/test/zlib/zlib-1.2.8/zlib.h @@ -0,0 +1,1768 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.8, April 28th, 2013 + + Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). +*/ + +#ifndef ZLIB_H +#define ZLIB_H + +#include "zconf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ZLIB_VERSION "1.2.8" +#define ZLIB_VERNUM 0x1280 +#define ZLIB_VER_MAJOR 1 +#define ZLIB_VER_MINOR 2 +#define ZLIB_VER_REVISION 8 +#define ZLIB_VER_SUBREVISION 0 + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed data. + This version of the library supports only one compression method (deflation) + but other algorithms will be added later and will have the same stream + interface. + + Compression can be done in a single step if the buffers are large enough, + or can be done by repeated calls of the compression function. In the latter + case, the application must provide more input and/or consume the output + (providing more output space) before each call. + + The compressed data format used by default by the in-memory functions is + the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped + around a deflate stream, which is itself documented in RFC 1951. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio using the functions that start + with "gz". The gzip format is different from the zlib format. gzip is a + gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. + + This library can optionally read and write gzip streams in memory as well. + + The zlib format was designed to be compact and fast for use in memory + and on communications channels. The gzip format was designed for single- + file compression on file systems, has a larger header than zlib to maintain + directory information, and uses a different, slower check method than zlib. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never crash + even in case of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + z_const Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total number of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total number of bytes output so far */ + + z_const char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: binary or text */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + gzip header information passed to and from zlib routines. See RFC 1952 + for more details on the meanings of these fields. +*/ +typedef struct gz_header_s { + int text; /* true if compressed data believed to be text */ + uLong time; /* modification time */ + int xflags; /* extra flags (not used when writing a gzip file) */ + int os; /* operating system */ + Bytef *extra; /* pointer to extra field or Z_NULL if none */ + uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ + uInt extra_max; /* space at extra (only when reading header) */ + Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ + uInt name_max; /* space at name (only when reading header) */ + Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ + uInt comm_max; /* space at comment (only when reading header) */ + int hcrc; /* true if there was or will be a header crc */ + int done; /* true when done reading gzip header (not used + when writing a gzip file) */ +} gz_header; + +typedef gz_header FAR *gz_headerp; + +/* + The application must update next_in and avail_in when avail_in has dropped + to zero. It must update next_out and avail_out when avail_out has dropped + to zero. The application must initialize zalloc, zfree and opaque before + calling the init function. All other fields are set by the compression + library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this if + the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers + returned by zalloc for objects of exactly 65536 bytes *must* have their + offset normalized to zero. The default allocation function provided by this + library ensures this (see zutil.c). To reduce memory requirements and avoid + any allocation of 64K objects, at the expense of compression ratio, compile + the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or progress + reports. After compression, total_in holds the total size of the + uncompressed data and may be saved for use in the decompressor (particularly + if the decompressor wants to decompress everything in a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +#define Z_BLOCK 5 +#define Z_TREES 6 +/* Allowed flush values; see deflate() and inflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative values + * are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_RLE 3 +#define Z_FIXED 4 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_TEXT 1 +#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ +#define Z_UNKNOWN 2 +/* Possible values of the data_type field (though see inflate()) */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + + /* basic functions */ + +ZEXTERN const char * ZEXPORT zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is not + compatible with the zlib.h header file used by the application. This check + is automatically made by deflateInit and inflateInit. + */ + +/* +ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, deflateInit updates them to use default + allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at all + (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION + requests a default compromise between speed and compression (currently + equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if level is not a valid compression level, or + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). msg is set to null + if there is no error message. deflateInit does not perform any compression: + this will be done by deflate(). +*/ + + +ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). Some + output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating avail_in or avail_out accordingly; avail_out should + never be zero before the call. The application can consume the compressed + output when it wants, for example when the output buffer is full (avail_out + == 0), or after each call of deflate(). If deflate returns Z_OK and with + zero avail_out, it must be called again after making room in the output + buffer because there might be more output pending. + + Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to + decide how much data to accumulate before producing output, in order to + maximize compression. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In + particular avail_in is zero after the call if enough output space has been + provided before the call.) Flushing may degrade compression for some + compression algorithms and so it should be used only when necessary. This + completes the current deflate block and follows it with an empty stored block + that is three bits plus filler bits to the next byte, followed by four bytes + (00 00 ff ff). + + If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the + output buffer, but the output is not aligned to a byte boundary. All of the + input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. + This completes the current deflate block and follows it with an empty fixed + codes block that is 10 bits long. This assures that enough bytes are output + in order for the decompressor to finish the block before the empty fixed code + block. + + If flush is set to Z_BLOCK, a deflate block is completed and emitted, as + for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to + seven bits of the current block are held to be written as the next byte after + the next deflate block is completed. In this case, the decompressor may not + be provided enough bits at this point in order to complete decompression of + the data provided so far to the compressor. It may need to wait for the next + block to be emitted. This is for advanced applications that need to control + the emission of deflate blocks. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that + avail_out is greater than six to avoid repeated flush markers due to + avail_out == 0 on return. + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there was + enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the stream + are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least the + value returned by deflateBound (see below). Then deflate is guaranteed to + return Z_STREAM_END. If not enough output space is provided, deflate will + not return Z_STREAM_END, and it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so far (that is, total_in bytes). + + deflate() may update strm->data_type if it can make a good guess about + the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered + binary. This field is only for information purposes and does not affect the + compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not + fatal, and deflate() can be called again with more input and more output + space to continue compressing. +*/ + + +ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, msg + may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the + exact value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit() does not process any header information -- that is deferred + until inflate() is called. +*/ + + +ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce + some output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing will + resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there is + no more input data or no more space in the output buffer (see below about + the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming more + output, and updating the next_* and avail_* values accordingly. The + application can consume the uncompressed output when it wants, for example + when the output buffer is full (avail_out == 0), or after each call of + inflate(). If inflate returns Z_OK and with zero avail_out, it must be + called again after making room in the output buffer because there might be + more output pending. + + The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, + Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much + output as possible to the output buffer. Z_BLOCK requests that inflate() + stop if and when it gets to the next deflate block boundary. When decoding + the zlib or gzip format, this will cause inflate() to return immediately + after the header and before the first block. When doing a raw inflate, + inflate() will go ahead and process the first block, and will return when it + gets to the end of that block, or when it runs out of data. + + The Z_BLOCK option assists in appending to or combining deflate streams. + Also to assist in this, on return inflate() will set strm->data_type to the + number of unused bits in the last byte taken from strm->next_in, plus 64 if + inflate() is currently decoding the last block in the deflate stream, plus + 128 if inflate() returned immediately after decoding an end-of-block code or + decoding the complete header up to just before the first byte of the deflate + stream. The end-of-block will not be indicated until all of the uncompressed + data from that block has been written to strm->next_out. The number of + unused bits may in general be greater than seven, except when bit 7 of + data_type is set, in which case the number of unused bits will be less than + eight. data_type is set as noted here every time inflate() returns for all + flush options, and so can be used to determine the amount of currently + consumed input in bits. + + The Z_TREES option behaves as Z_BLOCK does, but it also returns when the + end of each deflate block header is reached, before any actual data in that + block is decoded. This allows the caller to determine the length of the + deflate block header for later use in random access within a deflate block. + 256 is added to the value of strm->data_type when inflate() returns + immediately after reaching the end of the deflate block header. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step (a + single call of inflate), the parameter flush should be set to Z_FINISH. In + this case all pending input is processed and all pending output is flushed; + avail_out must be large enough to hold all of the uncompressed data for the + operation to complete. (The size of the uncompressed data may have been + saved by the compressor for this purpose.) The use of Z_FINISH is not + required to perform an inflation in one step. However it may be used to + inform inflate that a faster approach can be used for the single inflate() + call. Z_FINISH also informs inflate to not maintain a sliding window if the + stream completes, which reduces inflate's memory footprint. If the stream + does not complete, either because not all of the stream is provided or not + enough output space is provided, then a sliding window will be allocated and + inflate() can be called again to continue the operation as if Z_NO_FLUSH had + been used. + + In this implementation, inflate() always flushes as much output as + possible to the output buffer, and always uses the faster approach on the + first call. So the effects of the flush parameter in this implementation are + on the return value of inflate() as noted below, when inflate() returns early + when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of + memory for a sliding window when Z_FINISH is used. + + If a preset dictionary is needed after this call (see inflateSetDictionary + below), inflate sets strm->adler to the Adler-32 checksum of the dictionary + chosen by the compressor and returns Z_NEED_DICT; otherwise it sets + strm->adler to the Adler-32 checksum of all output produced so far (that is, + total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described + below. At the end of the stream, inflate() checks that its computed adler32 + checksum is equal to that saved by the compressor and returns Z_STREAM_END + only if the checksum is correct. + + inflate() can decompress and check either zlib-wrapped or gzip-wrapped + deflate data. The header type is detected automatically, if requested when + initializing with inflateInit2(). Any information contained in the gzip + header is not retained, so applications that need that information should + instead use raw inflate, see inflateInit2() below, or inflateBack() and + perform their own processing of the gzip header and trailer. When processing + gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output + producted so far. The CRC-32 is checked against the gzip trailer. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect check + value), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in the + output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + inflate() can be called again with more input and more output space to + continue decompressing. If Z_DATA_ERROR is returned, the application may + then call inflateSync() to look for a good compression block if a partial + recovery of the data is desired. +*/ + + +ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any pending + output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by the + caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits + determines the window size. deflate() will then generate raw deflate data + with no zlib header or trailer, and will not compute an adler32 check value. + + windowBits can also be greater than 15 for optional gzip encoding. Add + 16 to windowBits to write a simple gzip header and trailer around the + compressed data instead of a zlib wrapper. The gzip header will have no + file name, no extra data, no comment, no modification time (set to zero), no + header crc, and the operating system will be set to 255 (unknown). If a + gzip stream is being written, strm->adler is a crc32 instead of an adler32. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but is + slow and reduces compression ratio; memLevel=9 uses maximum memory for + optimal speed. The default value is 8. See zconf.h for total memory usage + as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match), or Z_RLE to limit match distances to one (run-length + encoding). Filtered data consists mostly of small values with a somewhat + random distribution. In this case, the compression algorithm is tuned to + compress them better. The effect of Z_FILTERED is to force more Huffman + coding and less string matching; it is somewhat intermediate between + Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as + fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The + strategy parameter only affects the compression ratio but not the + correctness of the compressed output even if it is not set appropriately. + Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler + decoder for special applications. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid + method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is + incompatible with the version assumed by the caller (ZLIB_VERSION). msg is + set to null if there is no error message. deflateInit2 does not perform any + compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. When using the zlib format, this + function must be called immediately after deflateInit, deflateInit2 or + deflateReset, and before any call of deflate. When doing raw deflate, this + function must be called either before any call of deflate, or immediately + after the completion of a deflate block, i.e. after all input has been + consumed and all output has been delivered when using any of the flush + options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The + compressor and decompressor must use exactly the same dictionary (see + inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size + provided in deflateInit or deflateInit2. Thus the strings most likely to be + useful should be put at the end of the dictionary, not at the front. In + addition, the current implementation of deflate will use at most the window + size minus 262 bytes of the provided dictionary. + + Upon return of this function, strm->adler is set to the adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) If a raw deflate was requested, then the + adler32 value is not computed and strm->adler is not set. + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if not at a block boundary for raw deflate). deflateSetDictionary does + not perform any compression: this will be done by deflate(). +*/ + +ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and can + consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. The + stream will keep the same compression level and any other attributes that + may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different strategy. + If the compression level is changed, the input available so far is + compressed with the old level (and may be flushed); the new level will take + effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to be + compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if + strm->avail_out was zero. +*/ + +ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, + int good_length, + int max_lazy, + int nice_length, + int max_chain)); +/* + Fine tune deflate's internal compression parameters. This should only be + used by someone who understands the algorithm used by zlib's deflate for + searching for the best matching string, and even then only by the most + fanatic optimizer trying to squeeze out the last compressed bit for their + specific input data. Read the deflate.c source code for the meaning of the + max_lazy, good_length, nice_length, and max_chain parameters. + + deflateTune() can be called after deflateInit() or deflateInit2(), and + returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. + */ + +ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, + uLong sourceLen)); +/* + deflateBound() returns an upper bound on the compressed size after + deflation of sourceLen bytes. It must be called after deflateInit() or + deflateInit2(), and after deflateSetHeader(), if used. This would be used + to allocate an output buffer for deflation in a single pass, and so would be + called before deflate(). If that first deflate() call is provided the + sourceLen input bytes, an output buffer allocated to the size returned by + deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed + to return Z_STREAM_END. Note that it is possible for the compressed size to + be larger than the value returned by deflateBound() if flush options other + than Z_FINISH or Z_NO_FLUSH are used. +*/ + +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, + unsigned *pending, + int *bits)); +/* + deflatePending() returns the number of bytes and bits of output that have + been generated, but not yet provided in the available output. The bytes not + provided would be due to the available output space having being consumed. + The number of bits of output not provided are between 0 and 7, where they + await more bits to join them in order to fill out a full byte. If pending + or bits are Z_NULL, then those values are not set. + + deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. + */ + +ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + deflatePrime() inserts bits in the deflate output stream. The intent + is that this function is used to start off the deflate output with the bits + leftover from a previous deflate stream when appending to it. As such, this + function can only be used for raw deflate, and must be used before the first + deflate() call after a deflateInit2() or deflateReset(). bits must be less + than or equal to 16, and that many of the least significant bits of value + will be inserted in the output. + + deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough + room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, + gz_headerp head)); +/* + deflateSetHeader() provides gzip header information for when a gzip + stream is requested by deflateInit2(). deflateSetHeader() may be called + after deflateInit2() or deflateReset() and before the first call of + deflate(). The text, time, os, extra field, name, and comment information + in the provided gz_header structure are written to the gzip header (xflag is + ignored -- the extra flags are set according to the compression level). The + caller must assure that, if not Z_NULL, name and comment are terminated with + a zero byte, and that if extra is not Z_NULL, that extra_len bytes are + available there. If hcrc is true, a gzip header crc is included. Note that + the current versions of the command-line version of gzip (up through version + 1.3.x) do not support header crc's, and will report that it is a "multi-part + gzip file" and give up. + + If deflateSetHeader is not used, the default gzip header has text false, + the time set to zero, and os set to 255, with no extra, name, or comment + fields. The gzip header is returned to the default state by deflateReset(). + + deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. windowBits must be greater than or equal to the windowBits value + provided to deflateInit2() while compressing, or it must be equal to 15 if + deflateInit2() was not used. If a compressed stream with a larger window + size is given as input, inflate() will return with the error code + Z_DATA_ERROR instead of trying to allocate a larger window. + + windowBits can also be zero to request that inflate use the window size in + the zlib header of the compressed stream. + + windowBits can also be -8..-15 for raw inflate. In this case, -windowBits + determines the window size. inflate() will then process raw deflate data, + not looking for a zlib or gzip header, not generating a check value, and not + looking for any check values for comparison at the end of the stream. This + is for use with other formats that use the deflate compressed data format + such as zip. Those formats provide their own check values. If a custom + format is developed using the raw deflate format for compressed data, it is + recommended that a check value such as an adler32 or a crc32 be applied to + the uncompressed data as is done in the zlib, gzip, and zip formats. For + most applications, the zlib format should be used as is. Note that comments + above on the use in deflateInit2() applies to the magnitude of windowBits. + + windowBits can also be greater than 15 for optional gzip decoding. Add + 32 to windowBits to enable zlib and gzip decoding with automatic header + detection, or add 16 to decode only the gzip format (the zlib format will + return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a + crc32 instead of an adler32. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller, or Z_STREAM_ERROR if the parameters are + invalid, such as a null pointer to the structure. msg is set to null if + there is no error message. inflateInit2 does not perform any decompression + apart from possibly reading the zlib header if present: actual decompression + will be done by inflate(). (So next_in and avail_in may be modified, but + next_out and avail_out are unused and unchanged.) The current implementation + of inflateInit2() does not process any header information -- that is + deferred until inflate() is called. +*/ + +ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate, + if that call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the adler32 value returned by that call of inflate. + The compressor and decompressor must use exactly the same dictionary (see + deflateSetDictionary). For raw inflate, this function can be called at any + time to set the dictionary. If the provided dictionary is smaller than the + window and there is already data in the window, then the provided dictionary + will amend what's there. The application must insure that the dictionary + that was used for compression is provided. + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by inflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If inflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a possible full flush point (see above + for the description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync searches for a 00 00 FF FF pattern in the compressed data. + All full flush points have this pattern, but not all occurrences of this + pattern are full flush points. + + inflateSync returns Z_OK if a possible full flush point has been found, + Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point + has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. + In the success case, the application may save the current current value of + total_in which indicates where valid compressed data was found. In the + error case, the application may repeatedly call inflateSync, providing more + input each time, until success or end of the input data. +*/ + +ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when randomly accessing a large stream. The + first pass through the stream can periodically record the inflate state, + allowing restarting inflate at those points when randomly accessing the + stream. + + inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being Z_NULL). msg is left unchanged in both source and + destination. +*/ + +ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. The + stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL). +*/ + +ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, + int windowBits)); +/* + This function is the same as inflateReset, but it also permits changing + the wrap and window size requests. The windowBits parameter is interpreted + the same as it is for inflateInit2. + + inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being Z_NULL), or if + the windowBits parameter is invalid. +*/ + +ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, + int bits, + int value)); +/* + This function inserts bits in the inflate input stream. The intent is + that this function is used to start inflating at a bit position in the + middle of a byte. The provided bits will be used before any bytes are used + from next_in. This function should only be used with raw inflate, and + should be used before the first inflate() call after inflateInit2() or + inflateReset(). bits must be less than or equal to 16, and that many of the + least significant bits of value will be inserted in the input. + + If bits is negative, then the input stream bit buffer is emptied. Then + inflatePrime() can be called again to put bits in the buffer. This is used + to clear out bits leftover after feeding inflate a block description prior + to feeding inflate codes. + + inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); +/* + This function returns two values, one in the lower 16 bits of the return + value, and the other in the remaining upper bits, obtained by shifting the + return value down 16 bits. If the upper value is -1 and the lower value is + zero, then inflate() is currently decoding information outside of a block. + If the upper value is -1 and the lower value is non-zero, then inflate is in + the middle of a stored block, with the lower value equaling the number of + bytes from the input remaining to copy. If the upper value is not -1, then + it is the number of bits back from the current bit position in the input of + the code (literal or length/distance pair) currently being processed. In + that case the lower value is the number of bytes already emitted for that + code. + + A code is being processed if inflate is waiting for more input to complete + decoding of the code, or if it has completed decoding but is waiting for + more output space to write the literal or match data. + + inflateMark() is used to mark locations in the input data for random + access, which may be at bit positions, and to note those cases where the + output of a code may span boundaries of random access blocks. The current + location in the input stream can be determined from avail_in and data_type + as noted in the description for the Z_BLOCK flush parameter for inflate. + + inflateMark returns the value noted above or -1 << 16 if the provided + source stream state was inconsistent. +*/ + +ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, + gz_headerp head)); +/* + inflateGetHeader() requests that gzip header information be stored in the + provided gz_header structure. inflateGetHeader() may be called after + inflateInit2() or inflateReset(), and before the first call of inflate(). + As inflate() processes the gzip stream, head->done is zero until the header + is completed, at which time head->done is set to one. If a zlib stream is + being decoded, then head->done is set to -1 to indicate that there will be + no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be + used to force inflate() to return immediately after header processing is + complete and before any actual data is decompressed. + + The text, time, xflags, and os fields are filled in with the gzip header + contents. hcrc is set to true if there is a header CRC. (The header CRC + was valid if done is set to one.) If extra is not Z_NULL, then extra_max + contains the maximum number of bytes to write to extra. Once done is true, + extra_len contains the actual extra field length, and extra contains the + extra field, or that field truncated if extra_max is less than extra_len. + If name is not Z_NULL, then up to name_max characters are written there, + terminated with a zero unless the length is greater than name_max. If + comment is not Z_NULL, then up to comm_max characters are written there, + terminated with a zero unless the length is greater than comm_max. When any + of extra, name, or comment are not Z_NULL and the respective field is not + present in the header, then that field is set to Z_NULL to signal its + absence. This allows the use of deflateSetHeader() with the returned + structure to duplicate the header. However if those fields are set to + allocated memory, then the application will need to save those pointers + elsewhere so that they can be eventually freed. + + If inflateGetHeader is not used, then the header information is simply + discarded. The header is always checked for validity, including the header + CRC if present. inflateReset() will reset the process to discard the header + information. The application would need to call inflateGetHeader() again to + retrieve the header from the next gzip stream. + + inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent. +*/ + +/* +ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, + unsigned char FAR *window)); + + Initialize the internal stream state for decompression using inflateBack() + calls. The fields zalloc, zfree and opaque in strm must be initialized + before the call. If zalloc and zfree are Z_NULL, then the default library- + derived memory allocation routines are used. windowBits is the base two + logarithm of the window size, in the range 8..15. window is a caller + supplied buffer of that size. Except for special applications where it is + assured that deflate was used with small window sizes, windowBits must be 15 + and a 32K byte window must be supplied to be able to decompress general + deflate streams. + + See inflateBack() for the usage of these routines. + + inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of + the parameters are invalid, Z_MEM_ERROR if the internal state could not be + allocated, or Z_VERSION_ERROR if the version of the library does not match + the version of the header file. +*/ + +typedef unsigned (*in_func) OF((void FAR *, + z_const unsigned char FAR * FAR *)); +typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); + +ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, + in_func in, void FAR *in_desc, + out_func out, void FAR *out_desc)); +/* + inflateBack() does a raw inflate with a single call using a call-back + interface for input and output. This is potentially more efficient than + inflate() for file i/o applications, in that it avoids copying between the + output and the sliding window by simply making the window itself the output + buffer. inflate() can be faster on modern CPUs when used with large + buffers. inflateBack() trusts the application to not change the output + buffer passed by the output function, at least until inflateBack() returns. + + inflateBackInit() must be called first to allocate the internal state + and to initialize the state with the user-provided window buffer. + inflateBack() may then be used multiple times to inflate a complete, raw + deflate stream with each call. inflateBackEnd() is then called to free the + allocated state. + + A raw deflate stream is one with no zlib or gzip header or trailer. + This routine would normally be used in a utility that reads zip or gzip + files and writes out uncompressed files. The utility would decode the + header and process the trailer on its own, hence this routine expects only + the raw deflate stream to decompress. This is different from the normal + behavior of inflate(), which expects either a zlib or gzip header and + trailer around the deflate stream. + + inflateBack() uses two subroutines supplied by the caller that are then + called by inflateBack() for input and output. inflateBack() calls those + routines until it reads a complete deflate stream and writes out all of the + uncompressed data, or until it encounters an error. The function's + parameters and return types are defined above in the in_func and out_func + typedefs. inflateBack() will call in(in_desc, &buf) which should return the + number of bytes of provided input, and a pointer to that input in buf. If + there is no input available, in() must return zero--buf is ignored in that + case--and inflateBack() will return a buffer error. inflateBack() will call + out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() + should return zero on success, or non-zero on failure. If out() returns + non-zero, inflateBack() will return with an error. Neither in() nor out() + are permitted to change the contents of the window provided to + inflateBackInit(), which is also the buffer that out() uses to write from. + The length written by out() will be at most the window size. Any non-zero + amount of input may be provided by in(). + + For convenience, inflateBack() can be provided input on the first call by + setting strm->next_in and strm->avail_in. If that input is exhausted, then + in() will be called. Therefore strm->next_in must be initialized before + calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called + immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in + must also be initialized, and then if strm->avail_in is not zero, input will + initially be taken from strm->next_in[0 .. strm->avail_in - 1]. + + The in_desc and out_desc parameters of inflateBack() is passed as the + first parameter of in() and out() respectively when they are called. These + descriptors can be optionally used to pass any information that the caller- + supplied in() and out() functions need to do their job. + + On return, inflateBack() will set strm->next_in and strm->avail_in to + pass back any unused input that was provided by the last in() call. The + return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR + if in() or out() returned an error, Z_DATA_ERROR if there was a format error + in the deflate stream (in which case strm->msg is set to indicate the nature + of the error), or Z_STREAM_ERROR if the stream was not properly initialized. + In the case of Z_BUF_ERROR, an input or output error can be distinguished + using strm->next_in which will be Z_NULL only if in() returned an error. If + strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning + non-zero. (in() will always be called before out(), so strm->next_in is + assured to be defined if out() returns non-zero.) Note that inflateBack() + cannot return Z_OK. +*/ + +ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); +/* + All memory allocated by inflateBackInit() is freed. + + inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream + state was inconsistent. +*/ + +ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); +/* Return flags indicating compile-time options. + + Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: + 1.0: size of uInt + 3.2: size of uLong + 5.4: size of voidpf (pointer) + 7.6: size of z_off_t + + Compiler, assembler, and debug options: + 8: DEBUG + 9: ASMV or ASMINF -- use ASM code + 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention + 11: 0 (reserved) + + One-time table building (smaller code, but not thread-safe if true): + 12: BUILDFIXED -- build static block decoding tables when needed + 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed + 14,15: 0 (reserved) + + Library content (indicates missing functionality): + 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking + deflate code when not needed) + 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect + and decode gzip streams (to avoid linking crc code) + 18-19: 0 (reserved) + + Operation variations (changes in library functionality): + 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate + 21: FASTEST -- deflate algorithm with only one, lowest compression level + 22,23: 0 (reserved) + + The sprintf variant used by gzprintf (zero is best): + 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format + 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! + 26: 0 = returns value, 1 = void -- 1 means inferred string length returned + + Remainder: + 27-31: 0 (reserved) + */ + +#ifndef Z_SOLO + + /* utility functions */ + +/* + The following utility functions are implemented on top of the basic + stream-oriented functions. To simplify the interface, some default options + are assumed (compression level and memory usage, standard memory allocation + functions). The source code of these utility functions can be modified if + you need special options. +*/ + +ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least the value returned by + compressBound(sourceLen). Upon exit, destLen is the actual size of the + compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); +/* + compressBound() returns an upper bound on the compressed size after + compress() or compress2() on sourceLen bytes. It would be used before a + compress() or compress2() call to allocate the destination buffer. +*/ + +ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, destLen + is the actual size of the uncompressed buffer. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In + the case where there is not enough room, uncompress() will fill the output + buffer with the uncompressed data up to that point. +*/ + + /* gzip file access functions */ + +/* + This library supports reading and writing files in gzip (.gz) format with + an interface similar to that of stdio, using the functions that start with + "gz". The gzip format is different from the zlib format. gzip is a gzip + wrapper, documented in RFC 1952, wrapped around a deflate stream. +*/ + +typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ + +/* +ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); + + Opens a gzip (.gz) file for reading or writing. The mode parameter is as + in fopen ("rb" or "wb") but can also include a compression level ("wb9") or + a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only + compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' + for fixed code compression as in "wb9F". (See the description of + deflateInit2 for more information about the strategy parameter.) 'T' will + request transparent writing or appending with no compression and not using + the gzip format. + + "a" can be used instead of "w" to request that the gzip stream that will + be written be appended to the file. "+" will result in an error, since + reading and writing to the same gzip file is not supported. The addition of + "x" when writing will create the file exclusively, which fails if the file + already exists. On systems that support it, the addition of "e" when + reading or writing will set the flag to close the file on an execve() call. + + These functions, as well as gzip, will read and decode a sequence of gzip + streams in a file. The append function of gzopen() can be used to create + such a file. (Also see gzflush() for another way to do this.) When + appending, gzopen does not test whether the file begins with a gzip stream, + nor does it look for the end of the gzip streams to begin appending. gzopen + will simply append a gzip stream to the existing file. + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. When + reading, this will be detected automatically by looking for the magic two- + byte gzip header. + + gzopen returns NULL if the file could not be opened, if there was + insufficient memory to allocate the gzFile state, or if an invalid mode was + specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). + errno can be checked to determine if the reason gzopen failed was that the + file could not be opened. +*/ + +ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); +/* + gzdopen associates a gzFile with the file descriptor fd. File descriptors + are obtained from calls like open, dup, creat, pipe or fileno (if the file + has been previously opened with fopen). The mode parameter is as in gzopen. + + The next call of gzclose on the returned gzFile will also close the file + descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor + fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, + mode);. The duplicated descriptor should be saved to avoid a leak, since + gzdopen does not close fd if it fails. If you are using fileno() to get the + file descriptor from a FILE *, then you will have to use dup() to avoid + double-close()ing the file descriptor. Both gzclose() and fclose() will + close the associated file descriptor, so they need to have different file + descriptors. + + gzdopen returns NULL if there was insufficient memory to allocate the + gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not + provided, or '+' was provided), or if fd is -1. The file descriptor is not + used until the next gz* read, write, seek, or close operation, so gzdopen + will not detect if fd is invalid (unless fd is -1). +*/ + +ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); +/* + Set the internal buffer size used by this library's functions. The + default buffer size is 8192 bytes. This function must be called after + gzopen() or gzdopen(), and before any other calls that read or write the + file. The buffer memory allocation is always deferred to the first read or + write. Two buffers are allocated, either both of the specified size when + writing, or one of the specified size and the other twice that size when + reading. A larger buffer size of, for example, 64K or 128K bytes will + noticeably increase the speed of decompression (reading). + + The new buffer size also affects the maximum length for gzprintf(). + + gzbuffer() returns 0 on success, or -1 on failure, such as being called + too late. +*/ + +ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. If + the input file is not in gzip format, gzread copies the given number of + bytes into the buffer directly from the file. + + After reaching the end of a gzip stream in the input, gzread will continue + to read, looking for another gzip stream. Any number of gzip streams may be + concatenated in the input file, and will all be decompressed by gzread(). + If something other than a gzip stream is encountered after a gzip stream, + that remaining trailing garbage is ignored (and no error is returned). + + gzread can be used to read a gzip file that is being concurrently written. + Upon reaching the end of the input, gzread will return with the available + data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then + gzclearerr can be used to clear the end of file indicator in order to permit + gzread to be tried again. Z_OK indicates that a gzip stream was completed + on the last gzread. Z_BUF_ERROR indicates that the input file ended in the + middle of a gzip stream. Note that gzread does not return -1 in the event + of an incomplete gzip stream. This error is deferred until gzclose(), which + will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip + stream. Alternatively, gzerror can be used before gzclose to detect this + case. + + gzread returns the number of uncompressed bytes actually read, less than + len for end of file, or -1 for error. +*/ + +ZEXTERN int ZEXPORT gzwrite OF((gzFile file, + voidpc buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes written or 0 in case of + error. +*/ + +ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the arguments to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written, or 0 in case of error. The number of + uncompressed bytes written is limited to 8191, or one less than the buffer + size given to gzbuffer(). The caller should assure that this limit is not + exceeded. If it is exceeded, then gzprintf() will return an error (0) with + nothing written. In this case, there may also be a buffer overflow with + unpredictable consequences, which is possible only if zlib was compiled with + the insecure functions sprintf() or vsprintf() because the secure snprintf() + or vsnprintf() functions were not available. This can be determined using + zlibCompileFlags(). +*/ + +ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + + gzputs returns the number of characters written, or -1 in case of error. +*/ + +ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or a + newline character is read and transferred to buf, or an end-of-file + condition is encountered. If any characters are read or if len == 1, the + string is terminated with a null character. If no characters are read due + to an end-of-file or len < 1, then the buffer is left untouched. + + gzgets returns buf which is a null-terminated string, or it returns NULL + for end-of-file or in case of error. If there was an error, the contents at + buf are indeterminate. +*/ + +ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. gzputc + returns the value that was written, or -1 in case of error. +*/ + +ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte or -1 + in case of end of file or error. This is implemented as a macro for speed. + As such, it does not do all of the checking the other functions do. I.e. + it does not check to see if file is NULL, nor whether the structure file + points to has been clobbered or not. +*/ + +ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); +/* + Push one character back onto the stream to be read as the first character + on the next read. At least one character of push-back is allowed. + gzungetc() returns the character pushed, or -1 on failure. gzungetc() will + fail if c is -1, and may fail if a character has been pushed but not read + yet. If gzungetc is used immediately after gzopen or gzdopen, at least the + output buffer size of pushed characters is allowed. (See gzbuffer above.) + The pushed character will be discarded if the stream is repositioned with + gzseek() or gzrewind(). +*/ + +ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter flush + is as in the deflate() function. The return value is the zlib error number + (see function gzerror below). gzflush is only permitted when writing. + + If the flush parameter is Z_FINISH, the remaining data is written and the + gzip stream is completed in the output. If gzwrite() is called again, a new + gzip stream will be started in the output. gzread() is able to read such + concatented gzip streams. + + gzflush should be called only when strictly necessary because it will + degrade compression if called too often. +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, + z_off_t offset, int whence)); + + Sets the starting position for the next gzread or gzwrite on the given + compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); + + Returns the starting position for the next gzread or gzwrite on the given + compressed file. This position represents a number of bytes in the + uncompressed data stream, and is zero when starting, even if appending or + reading a gzip stream from the middle of a file using gzdopen(). + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +/* +ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); + + Returns the current offset in the file being read or written. This offset + includes the count of bytes that precede the gzip stream, for example when + appending or when using gzdopen() for reading. When reading, the offset + does not include as yet unused buffered input. This information can be used + for a progress indicator. On error, gzoffset() returns -1. +*/ + +ZEXTERN int ZEXPORT gzeof OF((gzFile file)); +/* + Returns true (1) if the end-of-file indicator has been set while reading, + false (0) otherwise. Note that the end-of-file indicator is set only if the + read tried to go past the end of the input, but came up short. Therefore, + just like feof(), gzeof() may return false even if there is no more data to + read, in the event that the last read request was for the exact number of + bytes remaining in the input file. This will happen if the input file size + is an exact multiple of the buffer size. + + If gzeof() returns true, then the read functions will return no more data, + unless the end-of-file indicator is reset by gzclearerr() and the input file + has grown since the previous end of file was detected. +*/ + +ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); +/* + Returns true (1) if file is being copied directly while reading, or false + (0) if file is a gzip stream being decompressed. + + If the input file is empty, gzdirect() will return true, since the input + does not contain a gzip stream. + + If gzdirect() is used immediately after gzopen() or gzdopen() it will + cause buffers to be allocated to allow reading the file to determine if it + is a gzip file. Therefore if gzbuffer() is used, it should be called before + gzdirect(). + + When writing, gzdirect() returns true (1) if transparent writing was + requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: + gzdirect() is not needed when writing. Transparent writing must be + explicitly requested, so the application already knows the answer. When + linking statically, using gzdirect() will include all of the zlib code for + gzip file reading and decompression, which may not be desired.) +*/ + +ZEXTERN int ZEXPORT gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file and + deallocates the (de)compression state. Note that once file is closed, you + cannot call gzerror with file, since its structures have been deallocated. + gzclose must not be called more than once on the same file, just as free + must not be called more than once on the same allocation. + + gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a + file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the + last read ended in the middle of a gzip stream, or Z_OK on success. +*/ + +ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); +ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); +/* + Same as gzclose(), but gzclose_r() is only for use when reading, and + gzclose_w() is only for use when writing or appending. The advantage to + using these instead of gzclose() is that they avoid linking in zlib + compression or decompression code that is not used when only reading or only + writing respectively. If gzclose() is used, then both compression and + decompression code will be included the application when linking to a static + zlib library. +*/ + +ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the given + compressed file. errnum is set to zlib error number. If an error occurred + in the file system and not in the compression library, errnum is set to + Z_ERRNO and the application may consult errno to get the exact error code. + + The application must not modify the returned string. Future calls to + this function may invalidate the previously returned string. If file is + closed, then the string previously returned by gzerror will no longer be + available. + + gzerror() should be used to distinguish errors from end-of-file for those + functions above that do not distinguish those cases in their return values. +*/ + +ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); +/* + Clears the error and end-of-file flags for file. This is analogous to the + clearerr() function in stdio. This is useful for continuing to read a gzip + file that is being written concurrently. +*/ + +#endif /* !Z_SOLO */ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the compression + library. +*/ + +ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is Z_NULL, this function returns the + required initial value for the checksum. + + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. + + Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, + z_off_t len2)); + + Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 + and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for + each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of + seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note + that the z_off_t type (like off_t) is a signed integer. If len2 is + negative, the result has no meaning or utility. +*/ + +ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +/* + Update a running CRC-32 with the bytes buf[0..len-1] and return the + updated CRC-32. If buf is Z_NULL, this function returns the required + initial value for the crc. Pre- and post-conditioning (one's complement) is + performed within this function so it shouldn't be done by the application. + + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +/* +ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); + + Combine two CRC-32 check values into one. For two sequences of bytes, + seq1 and seq2 with lengths len1 and len2, CRC-32 check values were + calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 + check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and + len2. +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, + unsigned char FAR *window, + const char *version, + int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +#define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) + +#ifndef Z_SOLO + +/* gzgetc() macro and its supporting function and exposed data structure. Note + * that the real internal state is much larger than the exposed structure. + * This abbreviated structure exposes just enough for the gzgetc() macro. The + * user should not mess with these exposed elements, since their names or + * behavior could change in the future, perhaps even capriciously. They can + * only be used by the gzgetc() macro. You have been warned. + */ +struct gzFile_s { + unsigned have; + unsigned char *next; + z_off64_t pos; +}; +ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ +#ifdef Z_PREFIX_SET +# undef z_gzgetc +# define z_gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#else +# define gzgetc(g) \ + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) +#endif + +/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or + * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if + * both are true, the application gets the *64 functions, and the regular + * functions are changed to 64 bits) -- in case these are set on systems + * without large file support, _LFS64_LARGEFILE must also be true + */ +#ifdef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); + ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); +#endif + +#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) +# ifdef Z_PREFIX_SET +# define z_gzopen z_gzopen64 +# define z_gzseek z_gzseek64 +# define z_gztell z_gztell64 +# define z_gzoffset z_gzoffset64 +# define z_adler32_combine z_adler32_combine64 +# define z_crc32_combine z_crc32_combine64 +# else +# define gzopen gzopen64 +# define gzseek gzseek64 +# define gztell gztell64 +# define gzoffset gzoffset64 +# define adler32_combine adler32_combine64 +# define crc32_combine crc32_combine64 +# endif +# ifndef Z_LARGE64 + ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +# endif +#else + ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); + ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); + ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); + ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); +#endif + +#else /* Z_SOLO */ + + ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); + +#endif /* !Z_SOLO */ + +/* hack for buggy compilers */ +#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; +#endif + +/* undocumented functions */ +ZEXTERN const char * ZEXPORT zError OF((int)); +ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); +ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); +ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); +ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); +#if defined(_WIN32) && !defined(Z_SOLO) +ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, + const char *mode)); +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, + const char *format, + va_list va)); +# endif +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZLIB_H */ diff --git a/test/zlib/zlib-1.2.8/zlib.map b/test/zlib/zlib-1.2.8/zlib.map new file mode 100644 index 000000000..55c6647eb --- /dev/null +++ b/test/zlib/zlib-1.2.8/zlib.map @@ -0,0 +1,83 @@ +ZLIB_1.2.0 { + global: + compressBound; + deflateBound; + inflateBack; + inflateBackEnd; + inflateBackInit_; + inflateCopy; + local: + deflate_copyright; + inflate_copyright; + inflate_fast; + inflate_table; + zcalloc; + zcfree; + z_errmsg; + gz_error; + gz_intmax; + _*; +}; + +ZLIB_1.2.0.2 { + gzclearerr; + gzungetc; + zlibCompileFlags; +} ZLIB_1.2.0; + +ZLIB_1.2.0.8 { + deflatePrime; +} ZLIB_1.2.0.2; + +ZLIB_1.2.2 { + adler32_combine; + crc32_combine; + deflateSetHeader; + inflateGetHeader; +} ZLIB_1.2.0.8; + +ZLIB_1.2.2.3 { + deflateTune; + gzdirect; +} ZLIB_1.2.2; + +ZLIB_1.2.2.4 { + inflatePrime; +} ZLIB_1.2.2.3; + +ZLIB_1.2.3.3 { + adler32_combine64; + crc32_combine64; + gzopen64; + gzseek64; + gztell64; + inflateUndermine; +} ZLIB_1.2.2.4; + +ZLIB_1.2.3.4 { + inflateReset2; + inflateMark; +} ZLIB_1.2.3.3; + +ZLIB_1.2.3.5 { + gzbuffer; + gzoffset; + gzoffset64; + gzclose_r; + gzclose_w; +} ZLIB_1.2.3.4; + +ZLIB_1.2.5.1 { + deflatePending; +} ZLIB_1.2.3.5; + +ZLIB_1.2.5.2 { + deflateResetKeep; + gzgetc_; + inflateResetKeep; +} ZLIB_1.2.5.1; + +ZLIB_1.2.7.1 { + inflateGetDictionary; + gzvprintf; +} ZLIB_1.2.5.2; diff --git a/test/zlib/zlib-1.2.8/zlib.pc.cmakein b/test/zlib/zlib-1.2.8/zlib.pc.cmakein new file mode 100644 index 000000000..a5e642938 --- /dev/null +++ b/test/zlib/zlib-1.2.8/zlib.pc.cmakein @@ -0,0 +1,13 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@INSTALL_LIB_DIR@ +sharedlibdir=@INSTALL_LIB_DIR@ +includedir=@INSTALL_INC_DIR@ + +Name: zlib +Description: zlib compression library +Version: @VERSION@ + +Requires: +Libs: -L${libdir} -L${sharedlibdir} -lz +Cflags: -I${includedir} diff --git a/test/zlib/zlib-1.2.8/zlib.pc.in b/test/zlib/zlib-1.2.8/zlib.pc.in new file mode 100644 index 000000000..7e5acf9c7 --- /dev/null +++ b/test/zlib/zlib-1.2.8/zlib.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +sharedlibdir=@sharedlibdir@ +includedir=@includedir@ + +Name: zlib +Description: zlib compression library +Version: @VERSION@ + +Requires: +Libs: -L${libdir} -L${sharedlibdir} -lz +Cflags: -I${includedir} diff --git a/test/zlib/zlib-1.2.8/zlib2ansi b/test/zlib/zlib-1.2.8/zlib2ansi new file mode 100644 index 000000000..15e3e165f --- /dev/null +++ b/test/zlib/zlib-1.2.8/zlib2ansi @@ -0,0 +1,152 @@ +#!/usr/bin/perl + +# Transform K&R C function definitions into ANSI equivalent. +# +# Author: Paul Marquess +# Version: 1.0 +# Date: 3 October 2006 + +# TODO +# +# Asumes no function pointer parameters. unless they are typedefed. +# Assumes no literal strings that look like function definitions +# Assumes functions start at the beginning of a line + +use strict; +use warnings; + +local $/; +$_ = <>; + +my $sp = qr{ \s* (?: /\* .*? \*/ )? \s* }x; # assume no nested comments + +my $d1 = qr{ $sp (?: [\w\*\s]+ $sp)* $sp \w+ $sp [\[\]\s]* $sp }x ; +my $decl = qr{ $sp (?: \w+ $sp )+ $d1 }xo ; +my $dList = qr{ $sp $decl (?: $sp , $d1 )* $sp ; $sp }xo ; + + +while (s/^ + ( # Start $1 + ( # Start $2 + .*? # Minimal eat content + ( ^ \w [\w\s\*]+ ) # $3 -- function name + \s* # optional whitespace + ) # $2 - Matched up to before parameter list + + \( \s* # Literal "(" + optional whitespace + ( [^\)]+ ) # $4 - one or more anythings except ")" + \s* \) # optional whitespace surrounding a Literal ")" + + ( (?: $dList )+ ) # $5 + + $sp ^ { # literal "{" at start of line + ) # Remember to $1 + //xsom + ) +{ + my $all = $1 ; + my $prefix = $2; + my $param_list = $4 ; + my $params = $5; + + StripComments($params); + StripComments($param_list); + $param_list =~ s/^\s+//; + $param_list =~ s/\s+$//; + + my $i = 0 ; + my %pList = map { $_ => $i++ } + split /\s*,\s*/, $param_list; + my $pMatch = '(\b' . join('|', keys %pList) . '\b)\W*$' ; + + my @params = split /\s*;\s*/, $params; + my @outParams = (); + foreach my $p (@params) + { + if ($p =~ /,/) + { + my @bits = split /\s*,\s*/, $p; + my $first = shift @bits; + $first =~ s/^\s*//; + push @outParams, $first; + $first =~ /^(\w+\s*)/; + my $type = $1 ; + push @outParams, map { $type . $_ } @bits; + } + else + { + $p =~ s/^\s+//; + push @outParams, $p; + } + } + + + my %tmp = map { /$pMatch/; $_ => $pList{$1} } + @outParams ; + + @outParams = map { " $_" } + sort { $tmp{$a} <=> $tmp{$b} } + @outParams ; + + print $prefix ; + print "(\n" . join(",\n", @outParams) . ")\n"; + print "{" ; + +} + +# Output any trailing code. +print ; +exit 0; + + +sub StripComments +{ + + no warnings; + + # Strip C & C++ coments + # From the perlfaq + $_[0] =~ + + s{ + /\* ## Start of /* ... */ comment + [^*]*\*+ ## Non-* followed by 1-or-more *'s + ( + [^/*][^*]*\*+ + )* ## 0-or-more things which don't start with / + ## but do end with '*' + / ## End of /* ... */ comment + + | ## OR C++ Comment + // ## Start of C++ comment // + [^\n]* ## followed by 0-or-more non end of line characters + + | ## OR various things which aren't comments: + + ( + " ## Start of " ... " string + ( + \\. ## Escaped char + | ## OR + [^"\\] ## Non "\ + )* + " ## End of " ... " string + + | ## OR + + ' ## Start of ' ... ' string + ( + \\. ## Escaped char + | ## OR + [^'\\] ## Non '\ + )* + ' ## End of ' ... ' string + + | ## OR + + . ## Anything other char + [^/"'\\]* ## Chars which doesn't start a comment, string or escape + ) + }{$2}gxs; + +} diff --git a/test/zlib/zlib-1.2.8/zutil.c b/test/zlib/zlib-1.2.8/zutil.c new file mode 100644 index 000000000..23d2ebef0 --- /dev/null +++ b/test/zlib/zlib-1.2.8/zutil.c @@ -0,0 +1,324 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* @(#) $Id$ */ + +#include "zutil.h" +#ifndef Z_SOLO +# include "gzguts.h" +#endif + +#ifndef NO_DUMMY_DECL +struct internal_state {int dummy;}; /* for buggy compilers */ +#endif + +z_const char * const z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +const char * ZEXPORT zlibVersion() +{ + return ZLIB_VERSION; +} + +uLong ZEXPORT zlibCompileFlags() +{ + uLong flags; + + flags = 0; + switch ((int)(sizeof(uInt))) { + case 2: break; + case 4: flags += 1; break; + case 8: flags += 2; break; + default: flags += 3; + } + switch ((int)(sizeof(uLong))) { + case 2: break; + case 4: flags += 1 << 2; break; + case 8: flags += 2 << 2; break; + default: flags += 3 << 2; + } + switch ((int)(sizeof(voidpf))) { + case 2: break; + case 4: flags += 1 << 4; break; + case 8: flags += 2 << 4; break; + default: flags += 3 << 4; + } + switch ((int)(sizeof(z_off_t))) { + case 2: break; + case 4: flags += 1 << 6; break; + case 8: flags += 2 << 6; break; + default: flags += 3 << 6; + } +#ifdef DEBUG + flags += 1 << 8; +#endif +#if defined(ASMV) || defined(ASMINF) + flags += 1 << 9; +#endif +#ifdef ZLIB_WINAPI + flags += 1 << 10; +#endif +#ifdef BUILDFIXED + flags += 1 << 12; +#endif +#ifdef DYNAMIC_CRC_TABLE + flags += 1 << 13; +#endif +#ifdef NO_GZCOMPRESS + flags += 1L << 16; +#endif +#ifdef NO_GZIP + flags += 1L << 17; +#endif +#ifdef PKZIP_BUG_WORKAROUND + flags += 1L << 20; +#endif +#ifdef FASTEST + flags += 1L << 21; +#endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifdef NO_vsnprintf + flags += 1L << 25; +# ifdef HAS_vsprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_vsnprintf_void + flags += 1L << 26; +# endif +# endif +#else + flags += 1L << 24; +# ifdef NO_snprintf + flags += 1L << 25; +# ifdef HAS_sprintf_void + flags += 1L << 26; +# endif +# else +# ifdef HAS_snprintf_void + flags += 1L << 26; +# endif +# endif +#endif + return flags; +} + +#ifdef DEBUG + +# ifndef verbose +# define verbose 0 +# endif +int ZLIB_INTERNAL z_verbose = verbose; + +void ZLIB_INTERNAL z_error (m) + char *m; +{ + fprintf(stderr, "%s\n", m); + exit(1); +} +#endif + +/* exported to allow conversion of error code to string for compress() and + * uncompress() + */ +const char * ZEXPORT zError(err) + int err; +{ + return ERR_MSG(err); +} + +#if defined(_WIN32_WCE) + /* The Microsoft C Run-Time Library for Windows CE doesn't have + * errno. We define it as a global variable to simplify porting. + * Its value is always 0 and should not be used. + */ + int errno = 0; +#endif + +#ifndef HAVE_MEMCPY + +void ZLIB_INTERNAL zmemcpy(dest, source, len) + Bytef* dest; + const Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int ZLIB_INTERNAL zmemcmp(s1, s2, len) + const Bytef* s1; + const Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void ZLIB_INTERNAL zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifndef Z_SOLO + +#ifdef SYS16BIT + +#ifdef __TURBOC__ +/* Turbo C in 16-bit mode */ + +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} + +#endif /* __TURBOC__ */ + + +#ifdef M_I86 +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* M_I86 */ + +#endif /* SYS16BIT */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp malloc OF((uInt size)); +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : + (voidpf)calloc(items, size); +} + +void ZLIB_INTERNAL zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ + +#endif /* !Z_SOLO */ diff --git a/test/zlib/zlib-1.2.8/zutil.h b/test/zlib/zlib-1.2.8/zutil.h new file mode 100644 index 000000000..24ab06b1c --- /dev/null +++ b/test/zlib/zlib-1.2.8/zutil.h @@ -0,0 +1,253 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-2013 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* @(#) $Id$ */ + +#ifndef ZUTIL_H +#define ZUTIL_H + +#ifdef HAVE_HIDDEN +# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) +#else +# define ZLIB_INTERNAL +#endif + +#include "zlib.h" + +#if defined(STDC) && !defined(Z_SOLO) +# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) +# include +# endif +# include +# include +#endif + +#ifdef Z_SOLO + typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) +# define OS_CODE 0x00 +# ifndef Z_SOLO +# if defined(__TURBOC__) || defined(__BORLANDC__) +# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) + /* Allow compilation with ANSI keywords only enabled */ + void _Cdecl farfree( void *block ); + void *_Cdecl farmalloc( unsigned long nbytes ); +# else +# include +# endif +# else /* MSC or DJGPP */ +# include +# endif +# endif +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define F_OPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +# if defined(M_I86) && !defined(Z_SOLO) +# include +# endif +#endif + +#if defined(MACOS) || defined(TARGET_OS_MAC) +# define OS_CODE 0x07 +# ifndef Z_SOLO +# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os +# include /* for fdopen */ +# else +# ifndef fdopen +# define fdopen(fd,mode) NULL /* No fdopen() */ +# endif +# endif +# endif +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#ifdef WIN32 +# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ +# define OS_CODE 0x0b +# endif +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0f +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + +#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX +# if defined(_WIN32_WCE) +# define fdopen(fd,mode) NULL /* No fdopen() */ +# ifndef _PTRDIFF_T_DEFINED + typedef int ptrdiff_t; +# define _PTRDIFF_T_DEFINED +# endif +# else +# define fdopen(fd,type) _fdopen(fd,type) +# endif +#endif + +#if defined(__BORLANDC__) && !defined(MSDOS) + #pragma warn -8004 + #pragma warn -8008 + #pragma warn -8066 +#endif + +/* provide prototypes for these when building zlib without LFS */ +#if !defined(_WIN32) && \ + (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) + ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); + ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); +#endif + + /* common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#if defined(pyr) || defined(Z_SOLO) +# define NO_MEMCPY +#endif +#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + * The __SC__ check is for Symantec. + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); + int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); + void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG +# include + extern int ZLIB_INTERNAL z_verbose; + extern void ZLIB_INTERNAL z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) {if (z_verbose>=0) fprintf x ;} +# define Tracev(x) {if (z_verbose>0) fprintf x ;} +# define Tracevv(x) {if (z_verbose>1) fprintf x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +#ifndef Z_SOLO + voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, + unsigned size)); + void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); +#endif + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +/* Reverse the bytes in a 32-bit value */ +#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ + (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) + +#endif /* ZUTIL_H */ diff --git a/test/zlib/ztest.hpp b/test/zlib/ztest.hpp new file mode 100644 index 000000000..bbdcd5e6b --- /dev/null +++ b/test/zlib/ztest.hpp @@ -0,0 +1,167 @@ +// +// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// + +#ifndef BEAST_ZTEST_HPP +#define BEAST_ZTEST_HPP + +#include "zlib-1.2.8/zlib.h" +#include +#include +#include + +class z_deflator +{ + int level_ = Z_DEFAULT_COMPRESSION; + int windowBits_ = 15; + int memLevel_ = 4; + int strategy_ = Z_DEFAULT_STRATEGY; + +public: + // -1 = default + // 0 = none + // 1..9 = faster<-->better + void + level(int n) + { + level_ = n; + } + + void + windowBits(int n) + { + windowBits_ = n; + } + + void + memLevel(int n) + { + memLevel_ = n; + } + + void + strategy(int n) + { + strategy_ = n; + } + + std::string + operator()(std::string const& in) + { + int result; + z_stream zs; + memset(&zs, 0, sizeof(zs)); + result = deflateInit2( + &zs, + level_, + Z_DEFLATED, + -windowBits_, + memLevel_, + strategy_ + ); + if(result != Z_OK) + throw std::logic_error("deflateInit2 failed"); + std::string out; + out.resize(deflateBound(&zs, + static_cast(in.size()))); + zs.next_in = (Bytef*)in.data(); + zs.avail_in = static_cast(in.size()); + zs.next_out = (Bytef*)&out[0]; + zs.avail_out = static_cast(out.size()); + result = deflate(&zs, Z_FULL_FLUSH); + if(result != Z_OK) + throw std::logic_error("deflate failed"); + out.resize(zs.total_out); + deflateEnd(&zs); + return out; + } +}; + +class z_inflator +{ +public: + std::string + operator()(std::string const& in) + { + int result; + std::string out; + z_stream zs; + memset(&zs, 0, sizeof(zs)); + result = inflateInit2(&zs, -15); + try + { + zs.next_in = (Bytef*)in.data(); + zs.avail_in = static_cast(in.size()); + for(;;) + { + out.resize(zs.total_out + 1024); + zs.next_out = (Bytef*)&out[zs.total_out]; + zs.avail_out = static_cast( + out.size() - zs.total_out); + result = inflate(&zs, Z_SYNC_FLUSH); + if( result == Z_NEED_DICT || + result == Z_DATA_ERROR || + result == Z_MEM_ERROR) + { + throw std::logic_error("inflate failed"); + } + if(zs.avail_out > 0) + break; + if(result == Z_STREAM_END) + break; + } + out.resize(zs.total_out); + inflateEnd(&zs); + } + catch(...) + { + inflateEnd(&zs); + throw; + } + return out; + } +}; + +// Lots of repeats, limited char range +inline +std::string +corpus1(std::size_t n) +{ + static std::string const alphabet{ + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + }; + std::string s; + s.reserve(n + 5); + std::mt19937 g; + std::uniform_int_distribution d0{ + 0, alphabet.size() - 1}; + std::uniform_int_distribution d1{ + 1, 5}; + while(s.size() < n) + { + auto const rep = d1(g); + auto const ch = alphabet[d0(g)]; + s.insert(s.end(), rep, ch); + } + s.resize(n); + return s; +} + +// Random data +inline +std::string +corpus2(std::size_t n) +{ + std::string s; + s.reserve(n); + std::mt19937 g; + std::uniform_int_distribution d0{0, 255}; + while(n--) + s.push_back(static_cast(d0(g))); + return s; +} + +#endif