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