aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/configure.in7
-rw-r--r--erts/doc/src/zlib.xml12
-rw-r--r--erts/emulator/drivers/common/zlib_drv.c58
-rw-r--r--erts/preloaded/ebin/zlib.beambin14136 -> 14320 bytes
-rw-r--r--erts/preloaded/src/zlib.erl41
-rw-r--r--lib/kernel/test/zlib_SUITE.erl38
6 files changed, 124 insertions, 32 deletions
diff --git a/erts/configure.in b/erts/configure.in
index b1830979aa..9f3d267791 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -1359,6 +1359,8 @@ AC_ARG_ENABLE(builtin-zlib,
Z_LIB=
if test "x$enable_builtin_zlib" = "xyes"; then
+ AC_DEFINE(HAVE_ZLIB_INFLATEGETDICTIONARY, 1,
+ [Define if your zlib version defines inflateGetDictionary.])
AC_MSG_NOTICE([Using our own built-in zlib source])
else
AC_MSG_CHECKING(for zlib 1.2.5 or higher)
@@ -1385,6 +1387,11 @@ error
AC_MSG_RESULT(no)
])
LIBS=$zlib_save_LIBS
+
+AC_MSG_CHECKING(for zlib inflateGetDictionary presence)
+AC_SEARCH_LIBS(inflateGetDictionary, [z],
+ AC_DEFINE(HAVE_ZLIB_INFLATEGETDICTIONARY, 1,
+ [Define if your zlib version defines inflateGetDictionary.]))
fi
AC_SUBST(Z_LIB)
diff --git a/erts/doc/src/zlib.xml b/erts/doc/src/zlib.xml
index 138414a880..e1924fffee 100644
--- a/erts/doc/src/zlib.xml
+++ b/erts/doc/src/zlib.xml
@@ -576,6 +576,18 @@ unpack(Z, Compressed, Dict) ->
</func>
<func>
+ <name name="inflateGetDictionary" arity="1"/>
+ <fsummary>Return the decompression dictionary.</fsummary>
+ <desc>
+ <p>Returns the decompression dictionary currently in use
+ by the stream. This function must be called between
+ <seealso marker="#inflateInit/1"><c>inflateInit/1,2</c></seealso>
+ and <seealso marker="#inflateEnd/1"><c>inflateEnd</c></seealso>.</p>
+ <p>Only supported if ERTS was compiled with zlib >= 1.2.8.</p>
+ </desc>
+ </func>
+
+ <func>
<name name="open" arity="0"/>
<fsummary>Open a stream and return a stream reference.</fsummary>
<desc>
diff --git a/erts/emulator/drivers/common/zlib_drv.c b/erts/emulator/drivers/common/zlib_drv.c
index 440ba956d8..066cf87c9d 100644
--- a/erts/emulator/drivers/common/zlib_drv.c
+++ b/erts/emulator/drivers/common/zlib_drv.c
@@ -44,30 +44,34 @@
#define INFLATE_INIT 8
#define INFLATE_INIT2 9
#define INFLATE_SETDICT 10
-#define INFLATE_SYNC 11
-#define INFLATE_RESET 12
-#define INFLATE_END 13
-#define INFLATE 14
+#define INFLATE_GETDICT 11
+#define INFLATE_SYNC 12
+#define INFLATE_RESET 13
+#define INFLATE_END 14
+#define INFLATE 15
-#define CRC32_0 15
-#define CRC32_1 16
-#define CRC32_2 17
+#define CRC32_0 16
+#define CRC32_1 17
+#define CRC32_2 18
-#define SET_BUFSZ 18
-#define GET_BUFSZ 19
-#define GET_QSIZE 20
+#define SET_BUFSZ 19
+#define GET_BUFSZ 20
+#define GET_QSIZE 21
-#define ADLER32_1 21
-#define ADLER32_2 22
+#define ADLER32_1 22
+#define ADLER32_2 23
-#define CRC32_COMBINE 23
-#define ADLER32_COMBINE 24
+#define CRC32_COMBINE 24
+#define ADLER32_COMBINE 25
-#define INFLATE_CHUNK 25
+#define INFLATE_CHUNK 26
#define DEFAULT_BUFSZ 4000
+/* According to zlib documentation, it can never exceed this */
+#define INFL_DICT_SZ 32768
+
/* This flag is used in the same places, where zlib return codes
* (Z_OK, Z_STREAM_END, Z_NEED_DICT) are. So, we need to set it to
* relatively large value to avoid possible value clashes in future.
@@ -248,6 +252,20 @@ static int zlib_output(ZLibData* d)
return zlib_output_init(d);
}
+#ifdef HAVE_ZLIB_INFLATEGETDICTIONARY
+static int zlib_inflate_get_dictionary(ZLibData* d)
+{
+ ErlDrvBinary* dbin = driver_alloc_binary(INFL_DICT_SZ);
+ uInt dlen = 0;
+ int res = inflateGetDictionary(&d->s, (unsigned char*)dbin->orig_bytes, &dlen);
+ if ((res == Z_OK) && (driver_output_binary(d->port, NULL, 0, dbin, 0, dlen) < 0)) {
+ res = Z_ERRNO;
+ }
+ driver_free_binary(dbin);
+ return res;
+}
+#endif
+
static int zlib_inflate(ZLibData* d, int flush)
{
int res = Z_OK;
@@ -586,6 +604,16 @@ static ErlDrvSSizeT zlib_ctl(ErlDrvData drv_data, unsigned int command, char *bu
res = inflateSetDictionary(&d->s, (unsigned char*)buf, len);
return zlib_return(res, rbuf, rlen);
+ case INFLATE_GETDICT:
+#ifdef HAVE_ZLIB_INFLATEGETDICTIONARY
+ if (d->state != ST_INFLATE) goto badarg;
+ res = zlib_inflate_get_dictionary(d);
+ return zlib_return(res, rbuf, rlen);
+#else
+ errno = ENOTSUP;
+ return zlib_return(Z_ERRNO, rbuf, rlen);
+#endif
+
case INFLATE_SYNC:
if (d->state != ST_INFLATE) goto badarg;
if (len != 0) goto badarg;
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index 4c48742344..6a7ad9164f 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl
index fa0f28c5c3..8cd3e39fd7 100644
--- a/erts/preloaded/src/zlib.erl
+++ b/erts/preloaded/src/zlib.erl
@@ -23,7 +23,8 @@
-export([open/0,close/1,deflateInit/1,deflateInit/2,deflateInit/6,
deflateSetDictionary/2,deflateReset/1,deflateParams/3,
deflate/2,deflate/3,deflateEnd/1,
- inflateInit/1,inflateInit/2,inflateSetDictionary/2,
+ inflateInit/1,inflateInit/2,
+ inflateSetDictionary/2,inflateGetDictionary/1,
inflateSync/1,inflateReset/1,inflate/2,inflateEnd/1,
inflateChunk/1, inflateChunk/2,
setBufSize/2,getBufSize/1,
@@ -98,25 +99,26 @@
-define(INFLATE_INIT, 8).
-define(INFLATE_INIT2, 9).
-define(INFLATE_SETDICT, 10).
--define(INFLATE_SYNC, 11).
--define(INFLATE_RESET, 12).
--define(INFLATE_END, 13).
--define(INFLATE, 14).
--define(INFLATE_CHUNK, 25).
+-define(INFLATE_GETDICT, 11).
+-define(INFLATE_SYNC, 12).
+-define(INFLATE_RESET, 13).
+-define(INFLATE_END, 14).
+-define(INFLATE, 15).
+-define(INFLATE_CHUNK, 26).
--define(CRC32_0, 15).
--define(CRC32_1, 16).
--define(CRC32_2, 17).
+-define(CRC32_0, 16).
+-define(CRC32_1, 17).
+-define(CRC32_2, 18).
--define(SET_BUFSZ, 18).
--define(GET_BUFSZ, 19).
--define(GET_QSIZE, 20).
+-define(SET_BUFSZ, 19).
+-define(GET_BUFSZ, 20).
+-define(GET_QSIZE, 21).
--define(ADLER32_1, 21).
--define(ADLER32_2, 22).
+-define(ADLER32_1, 22).
+-define(ADLER32_2, 23).
--define(CRC32_COMBINE, 23).
--define(ADLER32_COMBINE, 24).
+-define(CRC32_COMBINE, 24).
+-define(ADLER32_COMBINE, 25).
%%------------------------------------------------------------------------
@@ -242,6 +244,13 @@ inflateInit(Z, WindowBits) ->
inflateSetDictionary(Z, Dictionary) ->
call(Z, ?INFLATE_SETDICT, Dictionary).
+-spec inflateGetDictionary(Z) -> Dictionary when
+ Z :: zstream(),
+ Dictionary :: iolist().
+inflateGetDictionary(Z) ->
+ _ = call(Z, ?INFLATE_GETDICT, []),
+ collect(Z).
+
-spec inflateSync(zstream()) -> 'ok'.
inflateSync(Z) ->
call(Z, ?INFLATE_SYNC, []).
diff --git a/lib/kernel/test/zlib_SUITE.erl b/lib/kernel/test/zlib_SUITE.erl
index f8257bd20c..4b67fce9a8 100644
--- a/lib/kernel/test/zlib_SUITE.erl
+++ b/lib/kernel/test/zlib_SUITE.erl
@@ -83,7 +83,7 @@ groups() ->
[api_open_close, api_deflateInit,
api_deflateSetDictionary, api_deflateReset,
api_deflateParams, api_deflate, api_deflateEnd,
- api_inflateInit, api_inflateSetDictionary,
+ api_inflateInit, api_inflateSetDictionary, api_inflateGetDictionary,
api_inflateSync, api_inflateReset, api_inflate, api_inflateChunk,
api_inflateEnd, api_setBufsz, api_getBufsz, api_crc32,
api_adler32, api_getQSize, api_un_compress, api_un_zip,
@@ -288,6 +288,42 @@ api_inflateSetDictionary(Config) when is_list(Config) ->
?m({'EXIT',{stream_error,_}}, zlib:inflateSetDictionary(Z1,Dict)),
?m(ok, zlib:close(Z1)).
+%% Test inflateGetDictionary.
+api_inflateGetDictionary(Config) when is_list(Config) ->
+ Z1 = zlib:open(),
+ IsOperationSupported =
+ case catch zlib:inflateGetDictionary(Z1) of
+ {'EXIT',{einval,_}} -> true;
+ {'EXIT',{enotsup,_}} -> false
+ end,
+ _ = zlib:close(Z1),
+ api_inflateGetDictionary_if_supported(IsOperationSupported).
+
+api_inflateGetDictionary_if_supported(false) ->
+ {skip, "inflateGetDictionary/1 unsupported in current setup"};
+api_inflateGetDictionary_if_supported(true) ->
+ % Compress payload using custom dictionary
+ Z1 = zlib:open(),
+ ?m(ok, zlib:deflateInit(Z1)),
+ Dict = <<"foobar barfoo foo bar far boo">>,
+ ?m(_, zlib:deflateSetDictionary(Z1, Dict)),
+ Payload = <<"foobarbarbar">>,
+ Compressed = zlib:deflate(Z1, Payload, finish),
+ ?m(ok, zlib:close(Z1)),
+
+ % Decompress and test dictionary extraction
+ Z2 = zlib:open(),
+ ?m(ok, zlib:inflateInit(Z2)),
+ ?m(<<>>, iolist_to_binary(zlib:inflateGetDictionary(Z2))),
+ ?m({'EXIT',{stream_error,_}}, zlib:inflateSetDictionary(Z2, Dict)),
+ ?m({'EXIT',{{need_dictionary,_},_}}, zlib:inflate(Z2, Compressed)),
+ ?m(ok, zlib:inflateSetDictionary(Z2, Dict)),
+ ?m(Dict, iolist_to_binary(zlib:inflateGetDictionary(Z2))),
+ ?m(Payload, iolist_to_binary(zlib:inflate(Z2, Compressed))),
+ ?m(ok, zlib:close(Z2)),
+ ?m(?BARG, zlib:inflateSetDictionary(Z2, Dict)),
+ ok.
+
%% Test inflateSync.
api_inflateSync(Config) when is_list(Config) ->
{skip,"inflateSync/1 sucks"}.