111 lines
2.8 KiB
C
111 lines
2.8 KiB
C
/* tvbuff_zstd.c
|
|
* Copyright 2022, Kevin Albertson <kevin.eric.albertson [AT] gmail.com>
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
/*
|
|
* Decompress ZSTD: http://facebook.github.io/zstd/
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#ifdef HAVE_ZSTD
|
|
#include <zstd.h>
|
|
#endif
|
|
|
|
#include "proto.h" // DISSECTOR_ASSERT_HINT
|
|
#include "tvbuff.h"
|
|
|
|
#include "tvbuff-int.h" // tvb_add_to_chain
|
|
|
|
#define MAX_LOOP_ITERATIONS 100
|
|
|
|
tvbuff_t *tvb_uncompress_zstd(tvbuff_t *tvb, const int offset, int comprlen)
|
|
{
|
|
#ifndef HAVE_ZSTD
|
|
// Cast to void to silence unused warnings.
|
|
(void)tvb;
|
|
(void)offset;
|
|
(void)comprlen;
|
|
return NULL;
|
|
#else
|
|
ZSTD_inBuffer input = {tvb_memdup(NULL, tvb, offset, comprlen), comprlen, 0};
|
|
ZSTD_DStream *zds = ZSTD_createDStream();
|
|
size_t rc = 0;
|
|
uint8_t *uncompr = NULL;
|
|
size_t uncompr_len = 0;
|
|
bool ok = false;
|
|
int count = 0;
|
|
|
|
// ZSTD does not consume the last byte of the frame until it has flushed all of the decompressed data of the frame.
|
|
// Therefore, loop while there is more input.
|
|
ZSTD_outBuffer output = {g_malloc(ZSTD_DStreamOutSize()), ZSTD_DStreamOutSize(), 0};
|
|
while (input.pos < input.size && count < MAX_LOOP_ITERATIONS)
|
|
{
|
|
rc = ZSTD_decompressStream(zds, &output, &input);
|
|
if (ZSTD_isError(rc))
|
|
{
|
|
goto end;
|
|
}
|
|
|
|
if (output.pos > 0)
|
|
{
|
|
if (!uncompr)
|
|
{
|
|
DISSECTOR_ASSERT (uncompr_len == 0);
|
|
uncompr = g_malloc(output.pos);
|
|
} else {
|
|
uncompr = g_realloc(uncompr, uncompr_len + output.pos);
|
|
}
|
|
memcpy (uncompr + uncompr_len, output.dst, output.pos);
|
|
uncompr_len += output.pos;
|
|
// Reset the output buffer.
|
|
output.pos = 0;
|
|
}
|
|
count++;
|
|
DISSECTOR_ASSERT_HINT(count < MAX_LOOP_ITERATIONS, "MAX_LOOP_ITERATIONS exceeded");
|
|
}
|
|
if (rc > 0)
|
|
{
|
|
// There is extra data that was not decompressed.
|
|
goto end;
|
|
}
|
|
|
|
ok = true;
|
|
end:
|
|
g_free((void *)output.dst);
|
|
wmem_free(NULL, (void *)input.src);
|
|
ZSTD_freeDStream(zds);
|
|
if (ok)
|
|
{
|
|
tvbuff_t *uncompr_tvb;
|
|
uncompr_tvb = tvb_new_real_data (uncompr, (guint)uncompr_len, (guint)uncompr_len);
|
|
tvb_set_free_cb (uncompr_tvb, g_free);
|
|
return uncompr_tvb;
|
|
}
|
|
|
|
if (uncompr)
|
|
{
|
|
g_free (uncompr);
|
|
}
|
|
|
|
return NULL;
|
|
#endif /* HAVE_ZSTD */
|
|
}
|
|
|
|
tvbuff_t *tvb_child_uncompress_zstd(tvbuff_t *parent, tvbuff_t *tvb, const int offset, int comprlen)
|
|
{
|
|
tvbuff_t *uncompressed = tvb_uncompress_zstd(tvb, offset, comprlen);
|
|
if (!uncompressed)
|
|
{
|
|
return uncompressed;
|
|
}
|
|
tvb_add_to_chain(parent, uncompressed);
|
|
return uncompressed;
|
|
}
|