Qt: fix memleaks on opening a context menu
[metze/wireshark/wip.git] / wsutil / buffer.c
1 /* buffer.c
2  *
3  * Wiretap Library
4  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
5  *
6  * SPDX-License-Identifier: GPL-2.0-or-later
7  */
8 #include "config.h"
9
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include "buffer.h"
14
15 #define SMALL_BUFFER_SIZE (2 * 1024) /* Everyone still uses 1500 byte frames, right? */
16 static GPtrArray *small_buffers = NULL; /* Guaranteed to be at least SMALL_BUFFER_SIZE */
17 /* XXX - Add medium and large buffers? */
18
19 /* Initializes a buffer with a certain amount of allocated space */
20 void
21 ws_buffer_init(Buffer* buffer, gsize space)
22 {
23         g_assert(buffer);
24         if (G_UNLIKELY(!small_buffers)) small_buffers = g_ptr_array_sized_new(1024);
25
26         if (space <= SMALL_BUFFER_SIZE) {
27                 if (small_buffers->len > 0) {
28                         buffer->data = (guint8*) g_ptr_array_remove_index(small_buffers, small_buffers->len - 1);
29                 } else {
30                         buffer->data = (guint8*)g_malloc(SMALL_BUFFER_SIZE);
31                 }
32                 buffer->allocated = SMALL_BUFFER_SIZE;
33         } else {
34                 buffer->data = (guint8*)g_malloc(space);
35                 buffer->allocated = space;
36         }
37         buffer->start = 0;
38         buffer->first_free = 0;
39 }
40
41 /* Frees the memory used by a buffer */
42 void
43 ws_buffer_free(Buffer* buffer)
44 {
45         g_assert(buffer);
46         if (buffer->allocated == SMALL_BUFFER_SIZE) {
47                 g_ptr_array_add(small_buffers, buffer->data);
48         } else {
49                 g_free(buffer->data);
50         }
51         buffer->data = NULL;
52 }
53
54 /* Assures that there are 'space' bytes at the end of the used space
55         so that another routine can copy directly into the buffer space. After
56         doing that, the routine will also want to run
57         ws_buffer_increase_length(). */
58 void
59 ws_buffer_assure_space(Buffer* buffer, gsize space)
60 {
61         g_assert(buffer);
62         gsize available_at_end = buffer->allocated - buffer->first_free;
63         gsize space_used;
64         gboolean space_at_beginning;
65
66         /* If we've got the space already, good! */
67         if (space <= available_at_end) {
68                 return;
69         }
70
71         /* Maybe we don't have the space available at the end, but we would
72                 if we moved the used space back to the beginning of the
73                 allocation. The buffer could have become fragmented through lots
74                 of calls to ws_buffer_remove_start(). I'm using buffer->start as the
75                 same as 'available_at_start' in this comparison. */
76
77         /* or maybe there's just no more room. */
78
79         space_at_beginning = buffer->start >= space;
80         if (space_at_beginning || buffer->start > 0) {
81                 space_used = buffer->first_free - buffer->start;
82                 /* this memory copy better be safe for overlapping memory regions! */
83                 memmove(buffer->data, buffer->data + buffer->start, space_used);
84                 buffer->start = 0;
85                 buffer->first_free = space_used;
86         }
87         /*if (buffer->start >= space) {*/
88         if (space_at_beginning) {
89                 return;
90         }
91
92         /* We'll allocate more space */
93         buffer->allocated += space + 1024;
94         buffer->data = (guint8*)g_realloc(buffer->data, buffer->allocated);
95 }
96
97 void
98 ws_buffer_append(Buffer* buffer, guint8 *from, gsize bytes)
99 {
100         g_assert(buffer);
101         ws_buffer_assure_space(buffer, bytes);
102         memcpy(buffer->data + buffer->first_free, from, bytes);
103         buffer->first_free += bytes;
104 }
105
106 void
107 ws_buffer_remove_start(Buffer* buffer, gsize bytes)
108 {
109         g_assert(buffer);
110         if (buffer->start + bytes > buffer->first_free) {
111                 g_error("ws_buffer_remove_start trying to remove %" G_GINT64_MODIFIER "u bytes. s=%" G_GINT64_MODIFIER "u ff=%" G_GINT64_MODIFIER "u!\n",
112                         (guint64)bytes, (guint64)buffer->start,
113                         (guint64)buffer->first_free);
114                 /** g_error() does an abort() and thus never returns **/
115         }
116         buffer->start += bytes;
117
118         if (buffer->start == buffer->first_free) {
119                 buffer->start = 0;
120                 buffer->first_free = 0;
121         }
122 }
123
124
125 #ifndef SOME_FUNCTIONS_ARE_DEFINES
126 void
127 ws_buffer_clean(Buffer* buffer)
128 {
129         g_assert(buffer);
130         ws_buffer_remove_start(buffer, ws_buffer_length(buffer));
131 }
132 #endif
133
134 #ifndef SOME_FUNCTIONS_ARE_DEFINES
135 void
136 ws_buffer_increase_length(Buffer* buffer, gsize bytes)
137 {
138         g_assert(buffer);
139         buffer->first_free += bytes;
140 }
141 #endif
142
143 #ifndef SOME_FUNCTIONS_ARE_DEFINES
144 gsize
145 ws_buffer_length(Buffer* buffer)
146 {
147         g_assert(buffer);
148         return buffer->first_free - buffer->start;
149 }
150 #endif
151
152 #ifndef SOME_FUNCTIONS_ARE_DEFINES
153 guint8 *
154 ws_buffer_start_ptr(Buffer* buffer)
155 {
156         g_assert(buffer);
157         return buffer->data + buffer->start;
158 }
159 #endif
160
161 #ifndef SOME_FUNCTIONS_ARE_DEFINES
162 guint8 *
163 ws_buffer_end_ptr(Buffer* buffer)
164 {
165         g_assert(buffer);
166         return buffer->data + buffer->first_free;
167 }
168 #endif
169
170 #ifndef SOME_FUNCTIONS_ARE_DEFINES
171 void
172 ws_buffer_append_buffer(Buffer* buffer, Buffer* src_buffer)
173 {
174         g_assert(buffer);
175         ws_buffer_append(buffer, ws_buffer_start_ptr(src_buffer), ws_buffer_length(src_buffer));
176 }
177 #endif
178
179 void
180 ws_buffer_cleanup(void)
181 {
182         if (small_buffers) {
183                 g_ptr_array_set_free_func(small_buffers, g_free);
184                 g_ptr_array_free(small_buffers, TRUE);
185                 small_buffers = NULL;
186         }
187 }
188
189 /*
190  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
191  *
192  * Local variables:
193  * c-basic-offset: 8
194  * tab-width: 8
195  * indent-tabs-mode: t
196  * End:
197  *
198  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
199  * :indentSize=8:tabSize=8:noTabs=false:
200  */