2 * Decompression code for LZNT1. This encoding is used by
3 * Microsoft in various file formats and protocols including SMB3.
7 * Copyright (C) 2019 Aurélien Aptel
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald@wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * SPDX-License-Identifier: GPL-2.0-or-later
17 #include <epan/exceptions.h>
18 #include <epan/tvbuff.h>
19 #include <epan/wmem_scopes.h>
21 #define MAX_INPUT_SIZE (16*1024*1024) /* 16MB */
24 uncompress_chunk(tvbuff_t
*tvb
, int offset
, int in_size
, wmem_array_t
*obuf
)
26 int in_off
= 0, out_off
= 0, out_start
= 0;
28 unsigned i
, j
, val
, pos
;
30 out_start
= wmem_array_get_count(obuf
);
32 while (in_off
< in_size
) {
33 flags
= tvb_get_uint8(tvb
, offset
+in_off
);
35 for (i
= 0; i
< 8; i
++) {
36 if (0 == ((flags
>>i
)&1)) {
37 val
= tvb_get_uint8(tvb
, offset
+in_off
);
39 wmem_array_append_one(obuf
, val
);
42 unsigned f
, l_mask
= 0x0FFF, o_shift
= 12;
43 unsigned match_len
, match_off
;
45 f
= tvb_get_letohs(tvb
, offset
+in_off
);
54 match_len
= (f
& l_mask
) + 3;
55 match_off
= (f
>> o_shift
) + 1;
56 for (j
= 0; j
< match_len
; j
++) {
58 if (match_off
> (unsigned)out_off
)
60 if (wmem_array_try_index(obuf
, out_start
+out_off
-match_off
, &byte
))
62 wmem_array_append_one(obuf
, byte
);
66 if (in_off
== in_size
) {
76 do_uncompress(tvbuff_t
*tvb
, int offset
, int in_size
, wmem_array_t
*obuf
)
79 uint32_t header
, length
, i
;
85 if (!in_size
|| in_size
> MAX_INPUT_SIZE
)
88 while (in_off
< in_size
) {
89 header
= tvb_get_letohs(tvb
, offset
+in_off
);
91 length
= (header
& 0x0FFF) + 1;
92 if (!(header
& 0x8000)) {
93 for (i
= 0; i
< length
; i
++) {
94 uint8_t v
= tvb_get_uint8(tvb
, offset
+in_off
);
95 wmem_array_append_one(obuf
, v
);
99 ok
= uncompress_chunk(tvb
, offset
+ in_off
, length
, obuf
);
109 tvb_uncompress_lznt1(tvbuff_t
*tvb
, const int offset
, int in_size
)
111 volatile bool ok
= false;
112 wmem_allocator_t
*pool
;
116 pool
= wmem_allocator_new(WMEM_ALLOCATOR_SIMPLE
);
117 obuf
= wmem_array_sized_new(pool
, 1, in_size
*2);
120 ok
= do_uncompress(tvb
, offset
, in_size
, obuf
);
128 * Cannot pass a tvb free callback that frees the wmem
129 * pool, so we make an extra copy that uses bare
130 * pointers. This could be optimized if tvb API had a
131 * free pool callback of some sort.
133 unsigned size
= wmem_array_get_count(obuf
);
134 uint8_t *p
= (uint8_t *)g_malloc(size
);
135 memcpy(p
, wmem_array_get_raw(obuf
), size
);
136 out
= tvb_new_real_data(p
, size
, size
);
137 tvb_set_free_cb(out
, g_free
);
142 wmem_destroy_allocator(pool
);
148 tvb_child_uncompress_lznt1(tvbuff_t
*parent
, tvbuff_t
*tvb
, const int offset
, int in_size
)
150 tvbuff_t
*new_tvb
= tvb_uncompress_lznt1(tvb
, offset
, in_size
);
152 tvb_set_child_real_data_tvbuff(parent
, new_tvb
);
157 * Editor modelines - https://www.wireshark.org/tools/modelines.html
162 * indent-tabs-mode: t
165 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
166 * :indentSize=8:tabSize=8:noTabs=false: