2 * Decompression code for Plain LZ77. This encoding is used by
3 * Microsoft in various file formats and protocols including SMB3.
7 * Copyright (C) 2019 Aurélien Aptel
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include <epan/exceptions.h>
14 #include <epan/tvbuff.h>
15 #include <epan/wmem_scopes.h>
17 #define MAX_INPUT_SIZE (16*1024*1024) /* 16MB */
19 static bool do_uncompress(tvbuff_t
*tvb
, int offset
, int in_size
,
22 unsigned buf_flags
= 0, buf_flag_count
= 0;
24 int last_length_half_byte
= 0;
25 unsigned match_bytes
, match_len
, match_off
;
31 if (!in_size
|| in_size
> MAX_INPUT_SIZE
)
35 if (buf_flag_count
== 0) {
36 buf_flags
= tvb_get_letohl(tvb
, offset
+in_off
);
41 if ((buf_flags
& (1u << buf_flag_count
)) == 0) {
42 uint8_t v
= tvb_get_uint8(tvb
, offset
+in_off
);
43 wmem_array_append_one(obuf
, v
);
46 if (in_off
== in_size
)
48 match_bytes
= tvb_get_letohs(tvb
, offset
+in_off
);
50 match_len
= match_bytes
% 8;
51 match_off
= (match_bytes
/8) + 1;
53 if (last_length_half_byte
== 0) {
54 match_len
= tvb_get_uint8(tvb
, offset
+in_off
);
55 match_len
= match_len
% 16;
56 last_length_half_byte
= in_off
;
59 match_len
= tvb_get_uint8(tvb
, offset
+last_length_half_byte
);
60 match_len
= match_len
/ 16;
61 last_length_half_byte
= 0;
63 if (match_len
== 15) {
64 match_len
= tvb_get_uint8(tvb
, offset
+in_off
);
66 if (match_len
== 255) {
67 match_len
= tvb_get_letohs(tvb
, offset
+in_off
);
70 /* This case isn't documented */
71 match_len
= tvb_get_letohs(tvb
, offset
+in_off
);
76 match_len
-= (15 + 7);
83 for (i
= 0; i
< match_len
; i
++) {
85 if (match_off
> wmem_array_get_count(obuf
))
87 if (wmem_array_try_index(obuf
, wmem_array_get_count(obuf
)-match_off
, &byte
))
89 wmem_array_append_one(obuf
, byte
);
98 tvb_uncompress_lz77(tvbuff_t
*tvb
, const int offset
, int in_size
)
100 volatile bool ok
= false;
101 wmem_allocator_t
*pool
;
105 pool
= wmem_allocator_new(WMEM_ALLOCATOR_SIMPLE
);
106 obuf
= wmem_array_sized_new(pool
, 1, in_size
*2);
109 ok
= do_uncompress(tvb
, offset
, in_size
, obuf
);
117 * Cannot pass a tvb free callback that frees the wmem
118 * pool, so we make an extra copy that uses bare
119 * pointers. This could be optimized if tvb API had a
120 * free pool callback of some sort.
122 unsigned size
= wmem_array_get_count(obuf
);
123 uint8_t *p
= (uint8_t *)g_malloc(size
);
124 memcpy(p
, wmem_array_get_raw(obuf
), size
);
125 out
= tvb_new_real_data(p
, size
, size
);
126 tvb_set_free_cb(out
, g_free
);
131 wmem_destroy_allocator(pool
);
137 tvb_child_uncompress_lz77(tvbuff_t
*parent
, tvbuff_t
*tvb
, const int offset
, int in_size
)
139 tvbuff_t
*new_tvb
= tvb_uncompress_lz77(tvb
, offset
, in_size
);
141 tvb_set_child_real_data_tvbuff(parent
, new_tvb
);
147 * Editor modelines - https://www.wireshark.org/tools/modelines.html
152 * indent-tabs-mode: t
155 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
156 * :indentSize=8:tabSize=8:noTabs=false: