1 /*
2  * The bands data handle functions
3  *
4  * Copyright (C) 2010-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 "libmodi_bands_data_handle.h"
27 #include "libmodi_data_block.h"
28 #include "libmodi_definitions.h"
29 #include "libmodi_io_handle.h"
30 #include "libmodi_libbfio.h"
31 #include "libmodi_libcerror.h"
32 #include "libmodi_libcnotify.h"
33 #include "libmodi_libfdata.h"
34 #include "libmodi_libfcache.h"
35 #include "libmodi_unused.h"
36 
37 /* Creates bands data handle
38  * Make sure the value data_handle is referencing, is set to NULL
39  * Returns 1 if successful or -1 on error
40  */
libmodi_bands_data_handle_initialize(libmodi_bands_data_handle_t ** data_handle,libmodi_io_handle_t * io_handle,libcerror_error_t ** error)41 int libmodi_bands_data_handle_initialize(
42      libmodi_bands_data_handle_t **data_handle,
43      libmodi_io_handle_t *io_handle,
44      libcerror_error_t **error )
45 {
46 	static char *function = "libmodi_bands_data_handle_initialize";
47 
48 	if( data_handle == NULL )
49 	{
50 		libcerror_error_set(
51 		 error,
52 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
53 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
54 		 "%s: invalid data handle.",
55 		 function );
56 
57 		return( -1 );
58 	}
59 	if( *data_handle != NULL )
60 	{
61 		libcerror_error_set(
62 		 error,
63 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
64 		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
65 		 "%s: invalid data handle value already set.",
66 		 function );
67 
68 		return( -1 );
69 	}
70 	if( io_handle == NULL )
71 	{
72 		libcerror_error_set(
73 		 error,
74 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
75 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
76 		 "%s: invalid IO handle.",
77 		 function );
78 
79 		return( -1 );
80 	}
81 	*data_handle = memory_allocate_structure(
82 	                libmodi_bands_data_handle_t );
83 
84 	if( *data_handle == NULL )
85 	{
86 		libcerror_error_set(
87 		 error,
88 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
89 		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
90 		 "%s: unable to create data handle.",
91 		 function );
92 
93 		goto on_error;
94 	}
95 	if( memory_set(
96 	     *data_handle,
97 	     0,
98 	     sizeof( libmodi_bands_data_handle_t ) ) == NULL )
99 	{
100 		libcerror_error_set(
101 		 error,
102 		 LIBCERROR_ERROR_DOMAIN_MEMORY,
103 		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
104 		 "%s: unable to clear data handle.",
105 		 function );
106 
107 		memory_free(
108 		 *data_handle );
109 
110 		*data_handle = NULL;
111 
112 		return( -1 );
113 	}
114 	if( libfdata_vector_initialize(
115 	     &( ( *data_handle )->bands_vector ),
116 	     (size64_t) 512,
117 	     (intptr_t *) io_handle,
118 	     NULL,
119 	     NULL,
120 	     (int (*)(intptr_t *, intptr_t *, libfdata_vector_t *, libfdata_cache_t *, int, int, off64_t, size64_t, uint32_t, uint8_t, libcerror_error_t **)) &libmodi_data_block_read_vector_element_data,
121 	     NULL,
122 	     LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED,
123 	     error ) != 1 )
124 	{
125 		libcerror_error_set(
126 		 error,
127 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
128 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
129 		 "%s: unable to create bands vector.",
130 		 function );
131 
132 		goto on_error;
133 	}
134 	if( libfcache_cache_initialize(
135 	     &( ( *data_handle )->bands_cache ),
136 	     LIBMODI_MAXIMUM_CACHE_ENTRIES_DATA_BANDS,
137 	     error ) != 1 )
138 	{
139 		libcerror_error_set(
140 		 error,
141 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
142 		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
143 		 "%s: unable to create bands cache.",
144 		 function );
145 
146 		goto on_error;
147 	}
148 	return( 1 );
149 
150 on_error:
151 	if( *data_handle != NULL )
152 	{
153 		if( ( *data_handle )->bands_vector != NULL )
154 		{
155 			libfdata_vector_free(
156 			 &( ( *data_handle )->bands_vector ),
157 			 NULL );
158 		}
159 		memory_free(
160 		 *data_handle );
161 
162 		*data_handle = NULL;
163 	}
164 	return( -1 );
165 }
166 
167 /* Frees a data handle
168  * Returns 1 if successful or -1 on error
169  */
libmodi_bands_data_handle_free(libmodi_bands_data_handle_t ** data_handle,libcerror_error_t ** error)170 int libmodi_bands_data_handle_free(
171      libmodi_bands_data_handle_t **data_handle,
172      libcerror_error_t **error )
173 {
174 	static char *function = "libmodi_bands_data_handle_free";
175 	int result            = 1;
176 
177 	if( data_handle == NULL )
178 	{
179 		libcerror_error_set(
180 		 error,
181 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
182 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
183 		 "%s: invalid data handle.",
184 		 function );
185 
186 		return( -1 );
187 	}
188 	if( *data_handle != NULL )
189 	{
190 		if( libfcache_cache_free(
191 		     &( ( *data_handle )->bands_cache ),
192 		     error ) != 1 )
193 		{
194 			libcerror_error_set(
195 			 error,
196 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
197 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
198 			 "%s: unable to free bands cache.",
199 			 function );
200 
201 			result = -1;
202 		}
203 		if( libfdata_vector_free(
204 		     &( ( *data_handle )->bands_vector ),
205 		     error ) != 1 )
206 		{
207 			libcerror_error_set(
208 			 error,
209 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
210 			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
211 			 "%s: unable to free bands vector.",
212 			 function );
213 
214 			result = -1;
215 		}
216 		memory_free(
217 		 *data_handle );
218 
219 		*data_handle = NULL;
220 	}
221 	return( result );
222 }
223 
224 /* Appends a segment
225  * Returns 1 if successful or -1 on error
226  */
libmodi_bands_data_handle_append_segment(libmodi_bands_data_handle_t * data_handle,int segment_file_index,off64_t segment_offset,size64_t segment_size,uint32_t segment_flags,libcerror_error_t ** error)227 int libmodi_bands_data_handle_append_segment(
228      libmodi_bands_data_handle_t *data_handle,
229      int segment_file_index,
230      off64_t segment_offset,
231      size64_t segment_size,
232      uint32_t segment_flags,
233      libcerror_error_t **error )
234 {
235 	static char *function = "libmodi_bands_data_handle_append_segment";
236 	int segment_index     = 0;
237 
238 	if( data_handle == NULL )
239 	{
240 		libcerror_error_set(
241 		 error,
242 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
243 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
244 		 "%s: invalid data handle.",
245 		 function );
246 
247 		return( -1 );
248 	}
249 	if( libfdata_vector_append_segment(
250 	     data_handle->bands_vector,
251 	     &segment_index,
252 	     segment_file_index,
253 	     segment_offset,
254 	     segment_size,
255 	     segment_flags,
256 	     error ) != 1 )
257 	{
258 		libcerror_error_set(
259 		 error,
260 		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
261 		 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
262 		 "%s: unable to append segment to bands vector.",
263 		 function );
264 
265 		return( -1 );
266 	}
267 	return( 1 );
268 }
269 
270 /* Reads data from the current offset into a compressed
271  * Callback for the data stream
272  * Returns the number of bytes read or -1 on error
273  */
libmodi_bands_data_handle_read_segment_data(libmodi_bands_data_handle_t * data_handle,libbfio_handle_t * file_io_handle,int segment_index,int segment_file_index LIBMODI_ATTRIBUTE_UNUSED,uint8_t * segment_data,size_t segment_data_size,uint32_t segment_flags LIBMODI_ATTRIBUTE_UNUSED,uint8_t read_flags LIBMODI_ATTRIBUTE_UNUSED,libcerror_error_t ** error)274 ssize_t libmodi_bands_data_handle_read_segment_data(
275          libmodi_bands_data_handle_t *data_handle,
276          libbfio_handle_t *file_io_handle,
277          int segment_index,
278          int segment_file_index LIBMODI_ATTRIBUTE_UNUSED,
279          uint8_t *segment_data,
280          size_t segment_data_size,
281          uint32_t segment_flags LIBMODI_ATTRIBUTE_UNUSED,
282          uint8_t read_flags LIBMODI_ATTRIBUTE_UNUSED,
283          libcerror_error_t **error )
284 {
285 	libmodi_data_block_t *data_block = NULL;
286 	static char *function            = "libmodi_bands_data_handle_read_segment_data";
287 	size_t read_size                 = 0;
288 	size_t segment_data_offset       = 0;
289 	off64_t element_data_offset      = 0;
290 
291 	LIBMODI_UNREFERENCED_PARAMETER( segment_file_index )
292 	LIBMODI_UNREFERENCED_PARAMETER( segment_flags )
293 	LIBMODI_UNREFERENCED_PARAMETER( read_flags )
294 
295 	if( data_handle == NULL )
296 	{
297 		libcerror_error_set(
298 		 error,
299 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
300 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
301 		 "%s: invalid data handle.",
302 		 function );
303 
304 		return( -1 );
305 	}
306 	if( data_handle->current_offset < 0 )
307 	{
308 		libcerror_error_set(
309 		 error,
310 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
311 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
312 		 "%s: invalid data handle - current offset value out of bounds.",
313 		 function );
314 
315 		return( -1 );
316 	}
317 	if( segment_index < 0 )
318 	{
319 		libcerror_error_set(
320 		 error,
321 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
322 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
323 		 "%s: invalid segment index value out of bounds.",
324 		 function );
325 
326 		return( -1 );
327 	}
328 	if( segment_data == NULL )
329 	{
330 		libcerror_error_set(
331 		 error,
332 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
333 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
334 		 "%s: invalid segment data.",
335 		 function );
336 
337 		return( -1 );
338 	}
339 	if( segment_data_size > (size_t) SSIZE_MAX )
340 	{
341 		libcerror_error_set(
342 		 error,
343 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
344 		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
345 		 "%s: invalid segment data size value exceeds maximum.",
346 		 function );
347 
348 		return( -1 );
349 	}
350 	if( data_handle->data_size == 0 )
351 	{
352 		if( libfdata_vector_get_size(
353 		     data_handle->bands_vector,
354 		     &( data_handle->data_size ),
355 		     error ) != 1 )
356 		{
357 			libcerror_error_set(
358 			 error,
359 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
360 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
361 			 "%s: unable to retrieve size of bands vector.",
362 			 function );
363 
364 			return( -1 );
365 		}
366 	}
367 	if( (size64_t) data_handle->current_offset >= data_handle->data_size )
368 	{
369 		return( 0 );
370 	}
371 	while( segment_data_size > 0 )
372 	{
373 		if( libfdata_vector_get_element_value_at_offset(
374 		     data_handle->bands_vector,
375 		     (intptr_t *) file_io_handle,
376 		     (libfdata_cache_t *) data_handle->bands_cache,
377 		     data_handle->current_offset,
378 		     &element_data_offset,
379 		     (intptr_t **) &data_block,
380 		     0,
381 		     error ) != 1 )
382 		{
383 			libcerror_error_set(
384 			 error,
385 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
386 			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
387 			 "%s: unable to retrieve data block at offset: %" PRIi64 " (0x%08" PRIx64 ").",
388 			 function,
389 			 data_handle->current_offset,
390 			 data_handle->current_offset );
391 
392 			return( -1 );
393 		}
394 		if( data_block == NULL )
395 		{
396 			libcerror_error_set(
397 			 error,
398 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
399 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
400 			 "%s: invalid data block.",
401 			 function );
402 
403 			return( -1 );
404 		}
405 		if( data_block->data == NULL )
406 		{
407 			libcerror_error_set(
408 			 error,
409 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
410 			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
411 			 "%s: invalid data block - missing data.",
412 			 function );
413 
414 			return( -1 );
415 		}
416 		if( ( element_data_offset < 0 )
417 		 || ( (size64_t) element_data_offset >= data_block->data_size ) )
418 		{
419 			libcerror_error_set(
420 			 error,
421 			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
422 			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
423 			 "%s: invalid element data offset value out of bounds.",
424 			 function );
425 
426 			return( -1 );
427 		}
428 		read_size = data_block->data_size - element_data_offset;
429 
430 		if( read_size > segment_data_size )
431 		{
432 			read_size = segment_data_size;
433 		}
434 		if( memory_copy(
435 		     &( segment_data[ segment_data_offset ] ),
436 		     &( ( data_block->data )[ element_data_offset ] ),
437 		     read_size ) == NULL )
438 		{
439 			libcerror_error_set(
440 			 error,
441 			 LIBCERROR_ERROR_DOMAIN_MEMORY,
442 			 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
443 			 "%s: unable to copy block data.",
444 			 function );
445 
446 			return( -1 );
447 		}
448 		segment_data_offset += read_size;
449 		segment_data_size   -= read_size;
450 
451 		data_handle->current_offset += read_size;
452 
453 		if( (size64_t) data_handle->current_offset >= data_handle->data_size )
454 		{
455 			break;
456 		}
457 	}
458 	return( (ssize_t) segment_data_offset );
459 }
460 
461 /* Seeks a certain offset of the data
462  * Callback for the data stream
463  * Returns the offset if seek is successful or -1 on error
464  */
libmodi_bands_data_handle_seek_segment_offset(libmodi_bands_data_handle_t * data_handle,intptr_t * file_io_handle LIBMODI_ATTRIBUTE_UNUSED,int segment_index,int segment_file_index LIBMODI_ATTRIBUTE_UNUSED,off64_t segment_offset,libcerror_error_t ** error)465 off64_t libmodi_bands_data_handle_seek_segment_offset(
466          libmodi_bands_data_handle_t *data_handle,
467          intptr_t *file_io_handle LIBMODI_ATTRIBUTE_UNUSED,
468          int segment_index,
469          int segment_file_index LIBMODI_ATTRIBUTE_UNUSED,
470          off64_t segment_offset,
471          libcerror_error_t **error )
472 {
473 	static char *function = "libmodi_bands_data_handle_seek_segment_offset";
474 
475 	LIBMODI_UNREFERENCED_PARAMETER( file_io_handle )
476 	LIBMODI_UNREFERENCED_PARAMETER( segment_file_index )
477 
478 	if( data_handle == NULL )
479 	{
480 		libcerror_error_set(
481 		 error,
482 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
483 		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
484 		 "%s: invalid data handle.",
485 		 function );
486 
487 		return( -1 );
488 	}
489 	if( segment_index != 0 )
490 	{
491 		libcerror_error_set(
492 		 error,
493 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
494 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
495 		 "%s: invalid segment index value out of bounds.",
496 		 function );
497 
498 		return( -1 );
499 	}
500 	if( segment_offset < 0 )
501 	{
502 		libcerror_error_set(
503 		 error,
504 		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
505 		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
506 		 "%s: invalid segment offset value out of bounds.",
507 		 function );
508 
509 		return( -1 );
510 	}
511 	data_handle->current_offset = segment_offset;
512 
513 	return( segment_offset );
514 }
515 
516