/src/wireshark/epan/tvbuff_brotli.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* tvbuff_brotli.c |
2 | | * |
3 | | * Wireshark - Network traffic analyzer |
4 | | * By Gerald Combs <gerald@wireshark.org> |
5 | | * Copyright 1998 Gerald Combs |
6 | | * |
7 | | * SPDX-License-Identifier: GPL-2.0-or-later |
8 | | */ |
9 | | |
10 | | #include <config.h> |
11 | | |
12 | | #include <glib.h> |
13 | | |
14 | | #include <string.h> |
15 | | |
16 | | #ifdef HAVE_BROTLI |
17 | | #include <brotli/decode.h> |
18 | | #endif |
19 | | |
20 | | #include "tvbuff.h" |
21 | | |
22 | | #ifdef HAVE_BROTLI |
23 | | |
24 | | /* |
25 | | * 512KiB is the buffer size used by the brotli tool, so we |
26 | | * use that too. |
27 | | */ |
28 | | #define TVB_BROTLI_BUFSIZ (1 << 19) |
29 | | |
30 | | static void* |
31 | | brotli_g_malloc_wrapper(void *opaque _U_, size_t size) |
32 | | { |
33 | | return g_malloc(size); |
34 | | } |
35 | | |
36 | | static void |
37 | | brotli_g_free_wrapper(void *opaque _U_, void *address) |
38 | | { |
39 | | g_free(address); |
40 | | } |
41 | | |
42 | | /* |
43 | | * Uncompresses a brotli compressed packet inside a message of tvb at offset with |
44 | | * length comprlen. Returns an uncompressed tvbuffer if uncompression |
45 | | * succeeded or NULL if uncompression failed. |
46 | | */ |
47 | | |
48 | | tvbuff_t * |
49 | | tvb_uncompress_brotli(tvbuff_t *tvb, const int offset, int comprlen) |
50 | | { |
51 | | uint8_t *compr; |
52 | | uint8_t *uncompr = NULL; |
53 | | tvbuff_t *uncompr_tvb; |
54 | | BrotliDecoderState *decoder; |
55 | | uint8_t *strmbuf; |
56 | | const size_t bufsiz = TVB_BROTLI_BUFSIZ; |
57 | | size_t available_in; |
58 | | const uint8_t *next_in; |
59 | | size_t available_out; |
60 | | uint8_t *next_out; |
61 | | size_t total_out; |
62 | | unsigned needs_more_output; |
63 | | unsigned finished; |
64 | | |
65 | | if (tvb == NULL || comprlen <= 0) { |
66 | | return NULL; |
67 | | } |
68 | | |
69 | | compr = (uint8_t *)tvb_memdup(NULL, tvb, offset, comprlen); |
70 | | if (compr == NULL) { |
71 | | return NULL; |
72 | | } |
73 | | |
74 | | decoder = BrotliDecoderCreateInstance( |
75 | | &brotli_g_malloc_wrapper /*alloc_func*/, |
76 | | &brotli_g_free_wrapper /*free_func*/, |
77 | | NULL /*opaque*/); |
78 | | if (decoder == NULL) { |
79 | | wmem_free(NULL, compr); |
80 | | return NULL; |
81 | | } |
82 | | strmbuf = (uint8_t *)g_malloc(bufsiz); |
83 | | |
84 | | available_in = comprlen; |
85 | | next_in = compr; |
86 | | total_out = 0; |
87 | | needs_more_output = 0; |
88 | | finished = 0; |
89 | | while (available_in > 0 || needs_more_output) { |
90 | | needs_more_output = 0; |
91 | | available_out = bufsiz; |
92 | | next_out = strmbuf; |
93 | | |
94 | | BrotliDecoderResult result = BrotliDecoderDecompressStream( |
95 | | decoder, &available_in, &next_in, &available_out, &next_out, &total_out); |
96 | | switch (result) { |
97 | | case BROTLI_DECODER_RESULT_SUCCESS: |
98 | | if (available_in > 0) { |
99 | | goto cleanup; |
100 | | } |
101 | | finished = 1; |
102 | | break; |
103 | | case BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT: |
104 | | needs_more_output = 1; |
105 | | break; |
106 | | case BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT: |
107 | | /* |
108 | | * It's possible that not enough frames were captured |
109 | | * to decompress this fully, so return what we've done |
110 | | * so far, if any. |
111 | | */ |
112 | | break; |
113 | | case BROTLI_DECODER_RESULT_ERROR: |
114 | | default: |
115 | | goto cleanup; |
116 | | } |
117 | | |
118 | | /* |
119 | | * Check if decompressed size is too large. |
120 | | */ |
121 | | if (total_out > INT_MAX) { |
122 | | goto cleanup; |
123 | | } |
124 | | |
125 | | /* |
126 | | * BrotliDecoderDecompressStream sets available_out to the number of bytes |
127 | | * left unused from the buffer. But we are interested in the bytes it wrote |
128 | | * to the buffer in this pass, so we calculate pass_out. |
129 | | */ |
130 | | size_t pass_out = bufsiz - available_out; |
131 | | if (pass_out > 0) { |
132 | | uncompr = (uint8_t *)g_realloc(uncompr, total_out); |
133 | | memcpy(uncompr + (total_out - pass_out), strmbuf, pass_out); |
134 | | } |
135 | | } |
136 | | |
137 | | if (uncompr == NULL) { |
138 | | /* |
139 | | * This is for the case when the validly decompressed |
140 | | * length is 0. |
141 | | */ |
142 | | if (finished) { |
143 | | uncompr = (uint8_t *)g_strdup(""); |
144 | | } else { |
145 | | goto cleanup; |
146 | | } |
147 | | } |
148 | | |
149 | | uncompr_tvb = tvb_new_real_data((uint8_t *)uncompr, (unsigned)total_out, (int)total_out); |
150 | | tvb_set_free_cb(uncompr_tvb, g_free); |
151 | | |
152 | | g_free(strmbuf); |
153 | | wmem_free(NULL, compr); |
154 | | BrotliDecoderDestroyInstance(decoder); |
155 | | return uncompr_tvb; |
156 | | |
157 | | cleanup: |
158 | | g_free(strmbuf); |
159 | | g_free(uncompr); |
160 | | wmem_free(NULL, compr); |
161 | | BrotliDecoderDestroyInstance(decoder); |
162 | | return NULL; |
163 | | } |
164 | | #else |
165 | | tvbuff_t * |
166 | | tvb_uncompress_brotli(tvbuff_t *tvb _U_, const int offset _U_, int comprlen _U_) |
167 | 0 | { |
168 | 0 | return NULL; |
169 | 0 | } |
170 | | #endif |
171 | | |
172 | | tvbuff_t * |
173 | | tvb_child_uncompress_brotli(tvbuff_t *parent, tvbuff_t *tvb, const int offset, int comprlen) |
174 | 0 | { |
175 | 0 | tvbuff_t *new_tvb = tvb_uncompress_brotli(tvb, offset, comprlen); |
176 | 0 | if (new_tvb) |
177 | 0 | tvb_set_child_real_data_tvbuff(parent, new_tvb); |
178 | 0 | return new_tvb; |
179 | 0 | } |
180 | | |
181 | | /* |
182 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
183 | | * |
184 | | * Local variables: |
185 | | * c-basic-offset: 4 |
186 | | * tab-width: 8 |
187 | | * indent-tabs-mode: nil |
188 | | * End: |
189 | | * |
190 | | * vi: set shiftwidth=4 tabstop=8 expandtab: |
191 | | * :indentSize=4:tabSize=8:noTabs=true: |
192 | | */ |