/* * The bands data handle functions * * Copyright (C) 2010-2021, Joachim Metz * * Refer to AUTHORS for acknowledgements. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ #include #include #include #include "libmodi_bands_data_handle.h" #include "libmodi_data_block.h" #include "libmodi_definitions.h" #include "libmodi_io_handle.h" #include "libmodi_libbfio.h" #include "libmodi_libcerror.h" #include "libmodi_libcnotify.h" #include "libmodi_libfdata.h" #include "libmodi_libfcache.h" #include "libmodi_unused.h" /* Creates bands data handle * Make sure the value data_handle is referencing, is set to NULL * Returns 1 if successful or -1 on error */ int libmodi_bands_data_handle_initialize( libmodi_bands_data_handle_t **data_handle, libmodi_io_handle_t *io_handle, libcerror_error_t **error ) { static char *function = "libmodi_bands_data_handle_initialize"; if( data_handle == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid data handle.", function ); return( -1 ); } if( *data_handle != NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, "%s: invalid data handle value already set.", function ); return( -1 ); } if( io_handle == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid IO handle.", function ); return( -1 ); } *data_handle = memory_allocate_structure( libmodi_bands_data_handle_t ); if( *data_handle == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_INSUFFICIENT, "%s: unable to create data handle.", function ); goto on_error; } if( memory_set( *data_handle, 0, sizeof( libmodi_bands_data_handle_t ) ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_SET_FAILED, "%s: unable to clear data handle.", function ); memory_free( *data_handle ); *data_handle = NULL; return( -1 ); } if( libfdata_vector_initialize( &( ( *data_handle )->bands_vector ), (size64_t) 512, (intptr_t *) io_handle, NULL, NULL, (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, NULL, LIBFDATA_DATA_HANDLE_FLAG_NON_MANAGED, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, "%s: unable to create bands vector.", function ); goto on_error; } if( libfcache_cache_initialize( &( ( *data_handle )->bands_cache ), LIBMODI_MAXIMUM_CACHE_ENTRIES_DATA_BANDS, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED, "%s: unable to create bands cache.", function ); goto on_error; } return( 1 ); on_error: if( *data_handle != NULL ) { if( ( *data_handle )->bands_vector != NULL ) { libfdata_vector_free( &( ( *data_handle )->bands_vector ), NULL ); } memory_free( *data_handle ); *data_handle = NULL; } return( -1 ); } /* Frees a data handle * Returns 1 if successful or -1 on error */ int libmodi_bands_data_handle_free( libmodi_bands_data_handle_t **data_handle, libcerror_error_t **error ) { static char *function = "libmodi_bands_data_handle_free"; int result = 1; if( data_handle == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid data handle.", function ); return( -1 ); } if( *data_handle != NULL ) { if( libfcache_cache_free( &( ( *data_handle )->bands_cache ), error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, "%s: unable to free bands cache.", function ); result = -1; } if( libfdata_vector_free( &( ( *data_handle )->bands_vector ), error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED, "%s: unable to free bands vector.", function ); result = -1; } memory_free( *data_handle ); *data_handle = NULL; } return( result ); } /* Appends a segment * Returns 1 if successful or -1 on error */ int 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 ) { static char *function = "libmodi_bands_data_handle_append_segment"; int segment_index = 0; if( data_handle == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid data handle.", function ); return( -1 ); } if( libfdata_vector_append_segment( data_handle->bands_vector, &segment_index, segment_file_index, segment_offset, segment_size, segment_flags, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_APPEND_FAILED, "%s: unable to append segment to bands vector.", function ); return( -1 ); } return( 1 ); } /* Reads data from the current offset into a compressed * Callback for the data stream * Returns the number of bytes read or -1 on error */ ssize_t 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 ) { libmodi_data_block_t *data_block = NULL; static char *function = "libmodi_bands_data_handle_read_segment_data"; size_t read_size = 0; size_t segment_data_offset = 0; off64_t element_data_offset = 0; LIBMODI_UNREFERENCED_PARAMETER( segment_file_index ) LIBMODI_UNREFERENCED_PARAMETER( segment_flags ) LIBMODI_UNREFERENCED_PARAMETER( read_flags ) if( data_handle == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid data handle.", function ); return( -1 ); } if( data_handle->current_offset < 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid data handle - current offset value out of bounds.", function ); return( -1 ); } if( segment_index < 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid segment index value out of bounds.", function ); return( -1 ); } if( segment_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid segment data.", function ); return( -1 ); } if( segment_data_size > (size_t) SSIZE_MAX ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM, "%s: invalid segment data size value exceeds maximum.", function ); return( -1 ); } if( data_handle->data_size == 0 ) { if( libfdata_vector_get_size( data_handle->bands_vector, &( data_handle->data_size ), error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve size of bands vector.", function ); return( -1 ); } } if( (size64_t) data_handle->current_offset >= data_handle->data_size ) { return( 0 ); } while( segment_data_size > 0 ) { if( libfdata_vector_get_element_value_at_offset( data_handle->bands_vector, (intptr_t *) file_io_handle, (libfdata_cache_t *) data_handle->bands_cache, data_handle->current_offset, &element_data_offset, (intptr_t **) &data_block, 0, error ) != 1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_GET_FAILED, "%s: unable to retrieve data block at offset: %" PRIi64 " (0x%08" PRIx64 ").", function, data_handle->current_offset, data_handle->current_offset ); return( -1 ); } if( data_block == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: invalid data block.", function ); return( -1 ); } if( data_block->data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: invalid data block - missing data.", function ); return( -1 ); } if( ( element_data_offset < 0 ) || ( (size64_t) element_data_offset >= data_block->data_size ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid element data offset value out of bounds.", function ); return( -1 ); } read_size = data_block->data_size - element_data_offset; if( read_size > segment_data_size ) { read_size = segment_data_size; } if( memory_copy( &( segment_data[ segment_data_offset ] ), &( ( data_block->data )[ element_data_offset ] ), read_size ) == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_COPY_FAILED, "%s: unable to copy block data.", function ); return( -1 ); } segment_data_offset += read_size; segment_data_size -= read_size; data_handle->current_offset += read_size; if( (size64_t) data_handle->current_offset >= data_handle->data_size ) { break; } } return( (ssize_t) segment_data_offset ); } /* Seeks a certain offset of the data * Callback for the data stream * Returns the offset if seek is successful or -1 on error */ off64_t 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 ) { static char *function = "libmodi_bands_data_handle_seek_segment_offset"; LIBMODI_UNREFERENCED_PARAMETER( file_io_handle ) LIBMODI_UNREFERENCED_PARAMETER( segment_file_index ) if( data_handle == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid data handle.", function ); return( -1 ); } if( segment_index != 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid segment index value out of bounds.", function ); return( -1 ); } if( segment_offset < 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid segment offset value out of bounds.", function ); return( -1 ); } data_handle->current_offset = segment_offset; return( segment_offset ); }