1 /*
2 * Range list value
3 *
4 * Copyright (C) 2006-2021, Joachim Metz <joachim.metz@gmail.com>
5 *
6 * Refer to AUTHORS for acknowledgements.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22 #include <common.h>
23 #include <memory.h>
24 #include <types.h>
25
26 #include "libcdata_libcerror.h"
27 #include "libcdata_range_list_value.h"
28
29 /* Creates a range list value
30 * Make sure the value range_list_value is referencing, is set to NULL
31 * Returns 1 if successful or -1 on error
32 */
libcdata_range_list_value_initialize(libcdata_range_list_value_t ** range_list_value,libcerror_error_t ** error)33 int libcdata_range_list_value_initialize(
34 libcdata_range_list_value_t **range_list_value,
35 libcerror_error_t **error )
36 {
37 static char *function = "libcdata_range_list_value_initialize";
38
39 if( range_list_value == NULL )
40 {
41 libcerror_error_set(
42 error,
43 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
44 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
45 "%s: invalid range list value.",
46 function );
47
48 return( -1 );
49 }
50 if( *range_list_value != NULL )
51 {
52 libcerror_error_set(
53 error,
54 LIBCERROR_ERROR_DOMAIN_RUNTIME,
55 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
56 "%s: invalid range list value value already set.",
57 function );
58
59 return( -1 );
60 }
61 *range_list_value = memory_allocate_structure(
62 libcdata_range_list_value_t );
63
64 if( *range_list_value == NULL )
65 {
66 libcerror_error_set(
67 error,
68 LIBCERROR_ERROR_DOMAIN_MEMORY,
69 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
70 "%s: unable to create range list value.",
71 function );
72
73 goto on_error;
74 }
75 if( memory_set(
76 *range_list_value,
77 0,
78 sizeof( libcdata_range_list_value_t ) ) == NULL )
79 {
80 libcerror_error_set(
81 error,
82 LIBCERROR_ERROR_DOMAIN_MEMORY,
83 LIBCERROR_MEMORY_ERROR_SET_FAILED,
84 "%s: unable to clear range list value.",
85 function );
86
87 goto on_error;
88 }
89 return( 1 );
90
91 on_error:
92 if( *range_list_value != NULL )
93 {
94 memory_free(
95 *range_list_value );
96
97 *range_list_value = NULL;
98 }
99 return( -1 );
100 }
101
102 /* Frees a range list value
103 * Uses the value_free_function to free the element value
104 * Returns 1 if successful or -1 on error
105 */
libcdata_range_list_value_free(libcdata_range_list_value_t ** range_list_value,int (* value_free_function)(intptr_t ** value,libcerror_error_t ** error),libcerror_error_t ** error)106 int libcdata_range_list_value_free(
107 libcdata_range_list_value_t **range_list_value,
108 int (*value_free_function)(
109 intptr_t **value,
110 libcerror_error_t **error ),
111 libcerror_error_t **error )
112 {
113 static char *function = "libcdata_range_list_value_free";
114 int result = 1;
115
116 if( range_list_value == NULL )
117 {
118 libcerror_error_set(
119 error,
120 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
121 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
122 "%s: invalid range list value.",
123 function );
124
125 return( -1 );
126 }
127 if( *range_list_value != NULL )
128 {
129 if( value_free_function != NULL )
130 {
131 if( value_free_function(
132 &( ( *range_list_value )->value ),
133 error ) != 1 )
134 {
135 libcerror_error_set(
136 error,
137 LIBCERROR_ERROR_DOMAIN_RUNTIME,
138 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
139 "%s: unable to free value.",
140 function );
141
142 result = -1;
143 }
144 }
145 memory_free(
146 *range_list_value );
147
148 *range_list_value = NULL;
149 }
150 return( result );
151 }
152
153 /* Clones the range list value
154 *
155 * The values are cloned using the value_clone_function
156 * On error the values are freed using the value_free_function
157 *
158 * Returns 1 if successful or -1 on error
159 */
libcdata_range_list_value_clone(libcdata_range_list_value_t ** destination_range_list_value,libcdata_range_list_value_t * source_range_list_value,int (* value_free_function)(intptr_t ** value,libcerror_error_t ** error),int (* value_clone_function)(intptr_t ** destination_value,intptr_t * source_value,libcerror_error_t ** error),libcerror_error_t ** error)160 int libcdata_range_list_value_clone(
161 libcdata_range_list_value_t **destination_range_list_value,
162 libcdata_range_list_value_t *source_range_list_value,
163 int (*value_free_function)(
164 intptr_t **value,
165 libcerror_error_t **error ),
166 int (*value_clone_function)(
167 intptr_t **destination_value,
168 intptr_t *source_value,
169 libcerror_error_t **error ),
170 libcerror_error_t **error )
171 {
172 static char *function = "libcdata_range_list_value_clone";
173
174 if( destination_range_list_value == NULL )
175 {
176 libcerror_error_set(
177 error,
178 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
179 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
180 "%s: invalid destination range list value.",
181 function );
182
183 return( -1 );
184 }
185 if( *destination_range_list_value != NULL )
186 {
187 libcerror_error_set(
188 error,
189 LIBCERROR_ERROR_DOMAIN_RUNTIME,
190 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
191 "%s: invalid destination range list value value already set.",
192 function );
193
194 return( -1 );
195 }
196 if( value_free_function == NULL )
197 {
198 libcerror_error_set(
199 error,
200 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
201 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
202 "%s: invalid value free function.",
203 function );
204
205 return( -1 );
206 }
207 if( value_clone_function == NULL )
208 {
209 libcerror_error_set(
210 error,
211 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
212 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
213 "%s: invalid value clone function.",
214 function );
215
216 return( -1 );
217 }
218 if( source_range_list_value == NULL )
219 {
220 *destination_range_list_value = NULL;
221
222 return( 1 );
223 }
224 *destination_range_list_value = memory_allocate_structure(
225 libcdata_range_list_value_t );
226
227 if( *destination_range_list_value == NULL )
228 {
229 libcerror_error_set(
230 error,
231 LIBCERROR_ERROR_DOMAIN_MEMORY,
232 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
233 "%s: unable to create destination range list value.",
234 function );
235
236 goto on_error;
237 }
238 if( memory_copy(
239 *destination_range_list_value,
240 source_range_list_value,
241 sizeof( libcdata_range_list_value_t ) ) == NULL )
242 {
243 libcerror_error_set(
244 error,
245 LIBCERROR_ERROR_DOMAIN_MEMORY,
246 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
247 "%s: unable to copy source to destination range list value.",
248 function );
249
250 memory_free(
251 *destination_range_list_value );
252
253 *destination_range_list_value = NULL;
254
255 return( -1 );
256 }
257 ( *destination_range_list_value )->value = NULL;
258
259 if( value_clone_function(
260 &( ( *destination_range_list_value )->value ),
261 source_range_list_value->value,
262 error ) != 1 )
263 {
264 libcerror_error_set(
265 error,
266 LIBCERROR_ERROR_DOMAIN_RUNTIME,
267 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
268 "%s: unable to create destination value.",
269 function );
270
271 goto on_error;
272 }
273 return( 1 );
274
275 on_error:
276 if( *destination_range_list_value != NULL )
277 {
278 if( ( *destination_range_list_value )->value != NULL )
279 {
280 value_free_function(
281 &( ( *destination_range_list_value )->value ),
282 NULL );
283 }
284 memory_free(
285 *destination_range_list_value );
286
287 *destination_range_list_value = NULL;
288 }
289 return( -1 );
290 }
291
292 /* Merges the range list values
293 *
294 * The values are merged using the value_merge_function.
295 * If the source value is NULL the merge function is not called.
296 *
297 * Returns 1 if successful or -1 on error
298 */
libcdata_range_list_value_merge(libcdata_range_list_value_t * destination_range_list_value,libcdata_range_list_value_t * source_range_list_value,int (* value_merge_function)(intptr_t * destination_value,intptr_t * source_value,libcerror_error_t ** error),libcerror_error_t ** error)299 int libcdata_range_list_value_merge(
300 libcdata_range_list_value_t *destination_range_list_value,
301 libcdata_range_list_value_t *source_range_list_value,
302 int (*value_merge_function)(
303 intptr_t *destination_value,
304 intptr_t *source_value,
305 libcerror_error_t **error ),
306 libcerror_error_t **error )
307 {
308 static char *function = "libcdata_range_list_value_merge";
309
310 if( destination_range_list_value == NULL )
311 {
312 libcerror_error_set(
313 error,
314 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
315 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
316 "%s: invalid destination range list value.",
317 function );
318
319 return( -1 );
320 }
321 if( source_range_list_value == NULL )
322 {
323 libcerror_error_set(
324 error,
325 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
326 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
327 "%s: invalid source range list value.",
328 function );
329
330 return( -1 );
331 }
332 if( source_range_list_value->value != NULL )
333 {
334 if( destination_range_list_value->value == NULL )
335 {
336 destination_range_list_value->value = source_range_list_value->value;
337 }
338 else
339 {
340 if( value_merge_function == NULL )
341 {
342 libcerror_error_set(
343 error,
344 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
345 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
346 "%s: invalid value merge function.",
347 function );
348
349 return( -1 );
350 }
351 if( value_merge_function(
352 destination_range_list_value->value,
353 source_range_list_value->value,
354 error ) != 1 )
355 {
356 libcerror_error_set(
357 error,
358 LIBCERROR_ERROR_DOMAIN_RUNTIME,
359 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
360 "%s: unable to merge source with destination value.",
361 function );
362
363 return( -1 );
364 }
365 }
366 }
367 if( destination_range_list_value->start > source_range_list_value->start )
368 {
369 /* Merge a preceding range
370 */
371 destination_range_list_value->size += destination_range_list_value->start - source_range_list_value->start;
372 destination_range_list_value->start = source_range_list_value->start;
373 }
374 if( destination_range_list_value->end < source_range_list_value->end )
375 {
376 /* Merge a successive range
377 */
378 destination_range_list_value->size += source_range_list_value->end - destination_range_list_value->end;
379 destination_range_list_value->end = source_range_list_value->end;
380 }
381 return( 1 );
382 }
383
384 /* Checks if the range overlaps with the range list value
385 * Returns 1 if the range overlaps, 0 if not or -1 on error
386 */
libcdata_range_list_value_check_range_overlap(libcdata_range_list_value_t * range_list_value,uint64_t range_start,uint64_t range_end,libcerror_error_t ** error)387 int libcdata_range_list_value_check_range_overlap(
388 libcdata_range_list_value_t *range_list_value,
389 uint64_t range_start,
390 uint64_t range_end,
391 libcerror_error_t **error )
392 {
393 static char *function = "libcdata_range_list_value_check_range_overlap";
394
395 if( range_list_value == NULL )
396 {
397 libcerror_error_set(
398 error,
399 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
400 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
401 "%s: invalid range list value.",
402 function );
403
404 return( -1 );
405 }
406 /* Check if the range overlaps the existing range entirely
407 */
408 if( ( range_start < range_list_value->start )
409 && ( range_end > range_list_value->end ) )
410 {
411 return( 1 );
412 }
413 /* Check if the range overlaps at the end of the existing range
414 */
415 if( ( range_start >= range_list_value->start )
416 && ( range_start <= range_list_value->end ) )
417 {
418 return( 1 );
419 }
420 /* Check if the range overlaps at the beginning of the existing range
421 */
422 if( ( range_end >= range_list_value->start )
423 && ( range_end <= range_list_value->end ) )
424 {
425 return( 1 );
426 }
427 return( 0 );
428 }
429
430