source: releases/0.11.0/lib/range_list.c@ 209

Last change on this file since 209 was 150, checked in by tim, 16 years ago

integrated talloc into most of the rest of the regfi library
fixed a length validation issue

  • Property svn:keywords set to Id
File size: 7.7 KB
Line 
1/*
2 * Copyright (C) 2008-2009 Timothy D. Morgan
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 *
17 * $Id: range_list.c 150 2009-03-02 02:17:46Z tim $
18 */
19
20#include "range_list.h"
21
22
23/*******************/
24/* Private symbols */
25/*******************/
26#define RANGE_LIST_ALLOC_SIZE 256
27
28#if 0 /* For debugging */
29#include <stdio.h>
30static void range_list_print(const range_list* rl)
31{
32 uint32_t i;
33 for(i=0; i<rl->size; i++)
34 fprintf(stderr, " %d=%p,%d,%d,%p", i, (void*)rl->elements[i],
35 rl->elements[i]->offset, rl->elements[i]->length,
36 rl->elements[i]->data);
37 fprintf(stderr, "\n");
38}
39#endif
40
41/*
42 * Inserts elem into rl at the specified index and updates rl->size.
43 * Memory reallocation of rl->elements is handled when necessary, and
44 * rl->elem_alloced is updated in this case.. Returns false if memory
45 * could not be allocated.
46 */
47static bool range_list_insert(range_list* rl, range_list_element* elem, uint32_t index)
48{
49 uint32_t i;
50 range_list_element** tmp;
51
52 if(rl->size == rl->elem_alloced)
53 {
54 tmp = talloc_realloc(rl, rl->elements, range_list_element*,
55 (rl->elem_alloced+RANGE_LIST_ALLOC_SIZE));
56 if(tmp == NULL)
57 return false;
58 rl->elements = tmp;
59 rl->elem_alloced += RANGE_LIST_ALLOC_SIZE;
60 }
61
62 /* Do the shuffle to the right. */
63 for(i=rl->size; i > index; i--)
64 rl->elements[i] = rl->elements[i-1];
65 rl->elements[index] = elem;
66
67 rl->size++;
68 return true;
69}
70
71/*
72 * Finds the element with the closest offset to that provided, such that
73 * the element's offset <= the provided offset. If no such element
74 * exists, this returns -1 which indicates that the provided offset
75 * appears before all elements.
76 */
77static int32_t range_list_find_previous(const range_list* rl, uint32_t offset)
78{
79 uint32_t h_idx, l_idx, cur_idx;
80 uint32_t h_val, l_val;
81 range_list_element* cur_elem;
82
83 if((rl->size == 0) || (offset < rl->elements[0]->offset))
84 return -1;
85
86 if(offset >= rl->elements[rl->size-1]->offset)
87 return rl->size-1;
88
89 h_idx = rl->size-1;
90 l_idx = 0;
91 while(h_idx != l_idx)
92 {
93 h_val = rl->elements[h_idx]->offset + rl->elements[h_idx]->length;
94 l_val = rl->elements[l_idx]->offset;
95 /* Make an educated guess as to the "middle" index based on the
96 * ratios of the offset and high/low values.
97 */
98 cur_idx = (uint32_t)ceil((((double)offset-l_val)/(h_val-l_val))*(h_idx-l_idx));
99 if(cur_idx > h_idx)
100 cur_idx = h_idx;
101 if(cur_idx < l_idx)
102 cur_idx = l_idx;
103 cur_elem = rl->elements[cur_idx];
104
105 if((offset >= cur_elem->offset) && (offset < rl->elements[cur_idx+1]->offset))
106 return cur_idx;
107
108 if(offset < cur_elem->offset)
109 h_idx = cur_idx-1;
110 else
111 l_idx = cur_idx+1;
112 }
113
114 return h_idx;
115}
116
117
118/******************/
119/* Public symbols */
120/******************/
121range_list* range_list_new()
122{
123 range_list* rl;
124
125 rl = talloc(NULL, range_list);
126 if(rl == NULL)
127 return NULL;
128
129 rl->elements = talloc_array(rl, range_list_element*, RANGE_LIST_ALLOC_SIZE);
130 if(rl->elements == NULL)
131 {
132 talloc_free(rl);
133 return NULL;
134 }
135
136 rl->elem_alloced = RANGE_LIST_ALLOC_SIZE;
137 rl->size = 0;
138
139 return rl;
140}
141
142
143void range_list_free(range_list* rl)
144{
145 if(rl != NULL)
146 talloc_free(rl);
147}
148
149
150uint32_t range_list_size(const range_list* rl)
151{
152 return rl->size;
153}
154
155
156
157bool range_list_add(range_list* rl, uint32_t offset, uint32_t length, void* data)
158{
159 uint32_t insert_index;
160 range_list_element* elem;
161 range_list_element* prev_elem;
162 /*fprintf(stderr, "DEBUG: rl->size=%d\n", rl->size);*/
163 /* Sorry, limited to 2**31-1 elements. */
164 if(rl->size >= 0x7FFFFFFF)
165 return false;
166
167 /* 0-length ranges aren't allowed. */
168 if(length == 0)
169 return false;
170
171 /* Check for integer overflows */
172 if((uint32_t)(offset+length) < offset || (uint32_t)(offset+length) < length)
173 return false;
174
175 /* Find insertion point and validate there are no overlaps */
176 insert_index = range_list_find_previous(rl, offset)+1;
177
178 /* Does the previous element overlap with this one? */
179 if(insert_index > 0)
180 {
181 prev_elem = rl->elements[insert_index-1];
182 if(offset < prev_elem->length + prev_elem->offset)
183 return false;
184 }
185
186 /* Does this new element overlap with the next one? */
187 if((insert_index+1 < rl->size)
188 && (offset+length > rl->elements[insert_index+1]->offset))
189 return false;
190
191 elem = talloc(rl->elements, range_list_element);
192 if(elem == NULL)
193 return false;
194 elem->offset = offset;
195 elem->length = length;
196 elem->data = data;
197
198 if(!range_list_insert(rl, elem, insert_index))
199 {
200 talloc_free(elem);
201 return false;
202 }
203
204 return true;
205}
206
207
208bool range_list_remove(range_list* rl, uint32_t index)
209{
210 uint32_t i;
211 range_list_element** tmp;
212
213 if(index >= rl->size)
214 return false;
215
216 talloc_free(rl->elements[index]);
217
218 /* Do the shuffle to the left. */
219 for(i=index; i < (rl->size-1); i++)
220 rl->elements[i] = rl->elements[i+1];
221 rl->elements[rl->size-1] = NULL;
222 rl->size--;
223
224 /* Try to keep memory usage down */
225 if(rl->size + 2 * RANGE_LIST_ALLOC_SIZE < rl->elem_alloced)
226 {
227 tmp = talloc_realloc(rl, rl->elements, range_list_element*,
228 (rl->elem_alloced-2*RANGE_LIST_ALLOC_SIZE));
229 if(tmp != NULL)
230 {
231 rl->elements = tmp;
232 rl->elem_alloced -= 2*RANGE_LIST_ALLOC_SIZE;
233 }
234 }
235
236 return true;
237}
238
239
240const range_list_element* range_list_get(const range_list* rl, uint32_t index)
241{
242 if(index >= rl->size)
243 return NULL;
244
245 return rl->elements[index];
246}
247
248
249int32_t range_list_find(const range_list* rl, uint32_t offset)
250{
251 uint32_t prev_idx;
252 range_list_element* elem;
253
254 if(rl->size == 0)
255 return -1;
256
257 if((offset < rl->elements[0]->offset)
258 || (offset > rl->elements[rl->size-1]->offset
259 + rl->elements[rl->size-1]->length))
260 return -2;
261
262 prev_idx = range_list_find_previous(rl, offset);
263 elem = rl->elements[prev_idx];
264 if(offset < elem->offset+elem->length)
265 return prev_idx;
266
267 return -3;
268}
269
270
271void* range_list_find_data(const range_list* rl, uint32_t offset)
272{
273 int32_t index = range_list_find(rl, offset);
274 if(index < 0)
275 return NULL;
276
277 return rl->elements[index]->data;
278}
279
280
281bool range_list_split_element(range_list* rl, uint32_t index, uint32_t offset)
282{
283 range_list_element* cur_elem;
284 range_list_element* new_elem;
285
286 if(index >= rl->size)
287 return false;
288
289 cur_elem = rl->elements[index];
290 if((offset <= cur_elem->offset)
291 || (offset >= cur_elem->offset+cur_elem->length))
292 return false;
293
294 new_elem = talloc(rl->elements, range_list_element);
295 if(new_elem == NULL)
296 return false;
297
298 new_elem->offset = offset;
299 new_elem->length = cur_elem->offset + cur_elem->length - offset;
300 new_elem->data = cur_elem->data;
301
302 if(!range_list_insert(rl, new_elem, index+1))
303 {
304 talloc_free(new_elem);
305 return false;
306 }
307
308 cur_elem->length = new_elem->offset - cur_elem->offset;
309
310 return true;
311}
312
313
314bool range_list_has_range(range_list* rl, uint32_t start, uint32_t length)
315{
316 int32_t idx1, idx2;
317
318 idx1 = range_list_find(rl, start);
319 if(idx1 < 0)
320 return false;
321
322 idx2 = range_list_find(rl, start+length);
323 if(idx2 < 0)
324 return false;
325
326 if(idx1 == idx2)
327 return true;
328
329 while(idx1 != idx2)
330 {
331 if(rl->elements[idx1]->offset + rl->elements[idx1]->length
332 != rl->elements[idx1+1]->offset)
333 return false;
334 idx1++;
335 }
336
337 return true;
338}
Note: See TracBrowser for help on using the repository browser.