Example #1
0
/* Determines the uncompressed data size from the LZFu header in the compressed data
 * Return 1 on success or -1 on error
 */
int lzfu_get_uncompressed_data_size(
     uint8_t *compressed_data,
     size_t compressed_data_size,
     size_t *uncompressed_data_size,
     libcerror_error_t **error )
{
	lzfu_header_t lzfu_header;

	uint8_t *lzfu_data                = 0;
	static char *function             = "lzfu_get_uncompressed_data_size";

	uint8_t lz_buffer[ 4096 ];

	uint8_t *lzfu_reference_data      = 0;
	size_t compressed_data_iterator   = 0;
	size_t uncompressed_data_iterator = 0;
	uint16_t lz_buffer_iterator       = 0;
	uint16_t reference_offset         = 0;
	uint16_t reference_size           = 0;
	uint16_t reference_iterator       = 0;
	uint8_t flag_byte_bit_mask        = 0;
	uint8_t flag_byte                 = 0;

	if( compressed_data == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid compressed data.",
		 function );

		return( -1 );
	}
	if( compressed_data_size > (size_t) SSIZE_MAX )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
		 "%s: invalid compressed data size value exceeds maximum.",
		 function );

		return( -1 );
	}
	if( uncompressed_data_size == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid uncompressed data size.",
		 function );

		return( -1 );
	}
	lzfu_data = compressed_data;

	byte_stream_copy_to_uint32_little_endian(
	 lzfu_data,
	 lzfu_header.compressed_data_size );

	lzfu_data += 4;

	byte_stream_copy_to_uint32_little_endian(
	 lzfu_data,
	 lzfu_header.uncompressed_data_size );

	lzfu_data += 4;

	byte_stream_copy_to_uint32_little_endian(
	 lzfu_data,
	 lzfu_header.signature );

	lzfu_data += 8;

	if( ( lzfu_header.signature != LZFU_SIGNATURE_COMPRESSED )
	 && ( lzfu_header.signature != LZFU_SIGNATURE_UNCOMPRESSED ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported compression signature: 0x%08" PRIx32 ".",
		 function,
		 lzfu_header.signature );

		return( -1 );
	}
	compressed_data_size -= sizeof( lzfu_header_t );

	/* The compressed data size includes 12 bytes of the header
	 */
	lzfu_header.compressed_data_size -= 12;

#ifdef X
	if( (size_t) lzfu_header.compressed_data_size != compressed_data_size )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_RANGE,
		 "%s: mismatch in compressed data size (%" PRIu32 " != %" PRIzd ").",
		 function,
		 lzfu_header.compressed_data_size,
		 compressed_data_size );

		return( -1 );
	}
#endif
	if( memory_copy(
	     lz_buffer,
	     lzfu_rtf_dictionary,
	     207 ) == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
		 "%s: unable to initialize lz buffer.",
		 function );

		return( -1 );
	}
	lz_buffer_iterator = 207;

	if( memory_set(
	     &( lz_buffer[ lz_buffer_iterator ] ),
	     0,
	     ( 4096 - lz_buffer_iterator ) ) == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
		 "%s: unable to clear lz buffer.",
		 function );

		return( -1 );
	}
	while( compressed_data_iterator < (size_t) lzfu_header.compressed_data_size )
	{
		flag_byte = lzfu_data[ compressed_data_iterator++ ];

		/* Check every bit in the chunk flag byte from LSB to MSB
		 */
		for( flag_byte_bit_mask = 0x01;
		     flag_byte_bit_mask != 0x00;
		     flag_byte_bit_mask <<= 1 )
		{
			if( compressed_data_iterator == (size_t) lzfu_header.compressed_data_size )
			{
				break;
			}
			/* Check if the byte value is a literal or a reference
			 */
			if( ( flag_byte & flag_byte_bit_mask ) == 0 )
			{
				lz_buffer[ lz_buffer_iterator++ ] = lzfu_data[ compressed_data_iterator ];

				uncompressed_data_iterator++;
				compressed_data_iterator++;

				/* Make sure the lz buffer iterator wraps around
				 */
				lz_buffer_iterator %= 4096;

				lz_buffer[ lz_buffer_iterator ] = 0;
			}
			else
			{
				lzfu_reference_data = &( lzfu_data[ compressed_data_iterator ] );

				compressed_data_iterator += 2;

				byte_stream_copy_to_uint16_big_endian(
				 lzfu_reference_data,
				 reference_offset );

				reference_size     = ( reference_offset & 0x000f ) + 2;
				reference_offset >>= 4;

				for( reference_iterator = 0; reference_iterator < reference_size; reference_iterator++ )
				{
					lz_buffer[ lz_buffer_iterator++ ] = lz_buffer[ reference_offset ];

					uncompressed_data_iterator++;
					reference_offset++;

					/* Make sure the lz buffer iterator and reference offset wrap around
					 */
					lz_buffer_iterator %= 4096;
					reference_offset   %= 4096;

					lz_buffer[ lz_buffer_iterator ] = 0;
				}
			}
		}
	}
	if( (size_t) ( lzfu_header.uncompressed_data_size + 2 ) != uncompressed_data_iterator )
	{
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: mismatch in uncompressed data size (in header: %" PRIu32 " != required: %" PRIzd ").\n",
			 function,
			 lzfu_header.uncompressed_data_size + 2,
			 uncompressed_data_iterator );
		}
	}
	/* Compensate for the 2 trailing zero bytes
	 */
	*uncompressed_data_size = lzfu_header.uncompressed_data_size + 2;

	return( 1 );
}
/* Reads the property set from the property set stream
 * Returns 1 if successful or -1 on error
 */
int libolecf_property_set_read(
     libolecf_property_set_t *property_set,
     libolecf_io_handle_t *io_handle,
     libolecf_item_t *property_set_stream,
     libcerror_error_t **error )
{
	olecf_property_set_header_t property_set_header;

	libolecf_internal_property_set_t *internal_property_set = NULL;
	libolecf_property_section_t *property_section           = NULL;
	static char *function                                   = "libolecf_property_set_read";
	off64_t section_list_entry_offset                       = 0;
	ssize_t read_count                                      = 0;
	uint32_t section_header_offset                          = 0;
	uint16_t number_of_sections                             = 0;
	uint16_t section_index                                  = 0;
	int sections_entry                                      = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	libcstring_system_character_t guid_string[ 48 ];

	libfguid_identifier_t *guid                             = NULL;
	int result                                              = 0;
#endif

	if( property_set == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid property set.",
		 function );

		return( -1 );
	}
	internal_property_set = (libolecf_internal_property_set_t *) property_set;

	if( libolecf_stream_seek_offset(
	     property_set_stream,
	     0,
	     SEEK_SET,
	     error ) == -1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_SEEK_FAILED,
		 "%s: unable to seek property set header offset: 0.",
		 function );

		goto on_error;
	}
	read_count = libolecf_stream_read_buffer(
	              property_set_stream,
	              (uint8_t *) &property_set_header,
	              sizeof( olecf_property_set_header_t ),
	              error );

	if( read_count != (ssize_t) sizeof( olecf_property_set_header_t ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_READ_FAILED,
		 "%s: unable to read property set header.",
		 function );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: property set header:\n",
		 function );
		libcnotify_print_data(
		 (uint8_t *) &property_set_header,
		 sizeof( olecf_property_set_header_t ),
		 0 );
	}
#endif
	if( ( property_set_header.byte_order[ 0 ] == 0xfe )
	 && ( property_set_header.byte_order[ 1 ] == 0xff ) )
	{
		internal_property_set->byte_order = LIBOLECF_ENDIAN_LITTLE;
	}
	else if( ( property_set_header.byte_order[ 0 ] == 0xff )
	      && ( property_set_header.byte_order[ 1 ] == 0xfe ) )
	{
		internal_property_set->byte_order = LIBOLECF_ENDIAN_BIG;
	}
	else
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported byte order: 0x%02" PRIx8 " 0x%02" PRIx8 ".",
		 function,
		 property_set_header.byte_order[ 0 ],
		 property_set_header.byte_order[ 1 ] );

		goto on_error;
	}
	if( internal_property_set->byte_order == LIBOLECF_ENDIAN_LITTLE )
	{
		byte_stream_copy_to_uint16_little_endian(
		 property_set_header.format,
		 internal_property_set->format );

		byte_stream_copy_to_uint32_little_endian(
		 property_set_header.system_version,
		 internal_property_set->system_version );

		byte_stream_copy_to_uint16_little_endian(
		 property_set_header.number_of_sections,
		 number_of_sections );
	}
	else if( internal_property_set->byte_order == LIBOLECF_ENDIAN_BIG )
	{
		byte_stream_copy_to_uint16_big_endian(
		 property_set_header.format,
		 internal_property_set->format );

		byte_stream_copy_to_uint32_big_endian(
		 property_set_header.system_version,
		 internal_property_set->system_version );

		byte_stream_copy_to_uint16_big_endian(
		 property_set_header.number_of_sections,
		 number_of_sections );
	}
	if( memory_copy(
	     internal_property_set->class_identifier,
	     property_set_header.class_identifier,
	     16 ) == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
		 "%s: unable to copy class identifier.",
		 function );

		goto on_error;
	}
/* TODO make sure the class identifier is set in little endian */

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: property set header byte order\t\t: 0x%02" PRIx8 " 0x%02" PRIx8 "\n",
		 function,
		 property_set_header.byte_order[ 0 ],
		 property_set_header.byte_order[ 1 ] );

		libcnotify_printf(
		 "%s: property set header format\t\t\t: %" PRIu16 "\n",
		 function,
		 internal_property_set->format );
		
		libcnotify_printf(
		 "%s: property set header system version\t\t: 0x%08" PRIx32 "\n",
		 function,
		 internal_property_set->system_version );

		if( libfguid_identifier_initialize(
		     &guid,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
			 "%s: unable to create GUID.",
			 function );

			goto on_error;
		}
		if( libfguid_identifier_copy_from_byte_stream(
		     guid,
		     internal_property_set->class_identifier,
		     16,
		     internal_property_set->byte_order,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
			 "%s: unable to copy byte stream to GUID.",
			 function );

			goto on_error;
		}
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
		result = libfguid_identifier_copy_to_utf16_string(
			  guid,
			  (uint16_t *) guid_string,
			  48,
			  LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
			  error );
#else
		result = libfguid_identifier_copy_to_utf8_string(
			  guid,
			  (uint8_t *) guid_string,
			  48,
			  LIBFGUID_STRING_FORMAT_FLAG_USE_LOWER_CASE,
			  error );
#endif
		if( result != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
			 "%s: unable to copy GUID to string.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "%s: property set header class identifier\t: %" PRIs_LIBCSTRING_SYSTEM " (%s : %s)\n",
		 function,
		 guid_string,
		 libfwps_format_class_identifier_get_identifier(
		  internal_property_set->class_identifier ),
		 libfwps_format_class_identifier_get_description(
		  internal_property_set->class_identifier ) );

		if( libfguid_identifier_free(
		     &guid,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
			 "%s: unable to free GUID.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "%s: property set header number of sections\t: %" PRIu16 "\n",
		 function,
		 number_of_sections );

		libcnotify_printf(
		 "\n" );
	}
#endif
	section_list_entry_offset = sizeof( olecf_property_set_header_t );

	for( section_index = 0;
	     section_index < (int) number_of_sections;
	     section_index++ )
	{
		if( libolecf_property_section_initialize(
		     &property_section,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
			 "%s: unable to create property section: %d.",
			 function,
			 section_index );

			goto on_error;
		}
		if( libolecf_stream_seek_offset(
		     property_set_stream,
		     section_list_entry_offset,
		     SEEK_SET,
		     error ) == -1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_SEEK_FAILED,
			 "%s: unable to seek property section list entry: %d offset: %" PRIi64 ".",
			 function,
			 section_index,
			 section_list_entry_offset );

			goto on_error;
		}
		if( libolecf_property_section_read_list_entry(
		     (libolecf_internal_property_section_t *) property_section,
		     property_set_stream,
		     internal_property_set->byte_order,
		     &section_header_offset,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read property section list entry: %d.",
			 function,
			 section_index );

			goto on_error;
		}
		if( libolecf_stream_get_offset(
		     property_set_stream,
		     &section_list_entry_offset,
		     error ) == -1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_SEEK_FAILED,
			 "%s: unable to retrieve property section list entry offset.",
			 function );

			goto on_error;
		}
		if( libolecf_property_section_read(
		     (libolecf_internal_property_section_t *) property_section,
		     io_handle,
		     property_set_stream,
		     section_header_offset,
		     internal_property_set->byte_order,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read property section: %d at offset: %" PRIu32 ".",
			 function,
			 section_index,
			 section_header_offset );

			goto on_error;
		}
		if( libcdata_array_append_entry(
		     internal_property_set->sections,
		     &sections_entry,
		     (intptr_t *) property_section,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
			 "%s: unable to append property section: %d to sections array.",
			 function,
			 section_index );

			goto on_error;
		}
		property_section = NULL;
	}
	return( 1 );

on_error:
#if defined( HAVE_DEBUG_OUTPUT )
	if( guid != NULL )
	{
		libfguid_identifier_free(
		 &guid,
		 NULL );
	}
#endif
	if( property_section != NULL )
	{
		libolecf_property_section_free(
		 &property_section,
		 NULL );
	}
	return( -1 );
}
Example #3
0
/* Sends a SCSI read track information to the file descriptor
 * Returns the number of bytes read if successful or -1 on error
 */
ssize_t libsmdev_scsi_read_track_information(
         int file_descriptor,
         uint32_t offset,
         uint8_t *response,
         size_t response_size,
         liberror_error_t **error )
{
	libsmdev_scsi_read_track_information_cdb_t command;

	uint8_t sense[ LIBSMDEV_SCSI_SENSE_SIZE ];

	static char *function  = "libsmdev_scsi_read_track_information";
	ssize_t response_count = 0;

	if( file_descriptor == -1 )
	{
		liberror_error_set(
		 error,
		 LIBERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid file descriptor.",
		 function );

		return( -1 );
	}
	if( response == NULL )
	{
		liberror_error_set(
		 error,
		 LIBERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid response.",
		 function );

		return( -1 );
	}
	if( response_size > (size_t) SSIZE_MAX )
	{
		liberror_error_set(
		 error,
		 LIBERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
		 "%s: invalid response size value exceeds maximum.",
		 function );

		return( -1 );
	}
	if( memory_set(
	     &command,
	     0,
	     sizeof( libsmdev_scsi_read_track_information_cdb_t ) ) == NULL )
	{
		liberror_error_set(
		 error,
		 LIBERROR_ERROR_DOMAIN_MEMORY,
		 LIBERROR_MEMORY_ERROR_SET_FAILED,
		 "%s: unable to clear command.",
		 function );

		return( -1 );
	}
	command.operation_code = LIBSMDEV_SCSI_OPERATION_CODE_READ_TRACK_INFORMATION;
	command.address_type   = LIBSMDEV_SCSI_TRACK_INFORMATION_ADDRESS_TYPE_LBA;

	byte_stream_copy_from_uint32_big_endian(
	 command.offset,
	 offset );

	byte_stream_copy_from_uint16_big_endian(
	 command.receive_size,
	 response_size );

	if( libsmdev_scsi_command(
	     file_descriptor,
	     (uint8_t *) &command,
	     sizeof( libsmdev_scsi_read_track_information_cdb_t ),
	     response,
	     response_size,
	     sense,
	     LIBSMDEV_SCSI_SENSE_SIZE,
	     error ) != 1 )
	{
		liberror_error_set(
		 error,
		 LIBERROR_ERROR_DOMAIN_IO,
		 LIBERROR_IO_ERROR_GENERIC,
		 "%s: SCSI READ TRACK INFORMATION command failed.",
		 function );

		return( -1 );
	}
	byte_stream_copy_to_uint16_big_endian(
	 response,
	 response_count );

	if( response_count > (ssize_t) response_size )
	{
		liberror_error_set(
		 error,
		 LIBERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
		 "%s: response too small.",
		 function );

		return( -1 );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libnotify_verbose != 0 )
	{
		libnotify_printf(
		 "%s: response:\n",
		 function );
		libnotify_print_data(
		 response,
		 response_count,
		 0 );
	}
#endif
	return( response_count );
}
Example #4
0
/* Decompresses data using LZFu compression
 * Returns 1 on success or -1 on error
 */
int lzfu_decompress(
     uint8_t *compressed_data,
     size_t compressed_data_size,
     uint8_t *uncompressed_data,
     size_t *uncompressed_data_size,
     libcerror_error_t **error )
{
	lzfu_header_t lzfu_header;
	uint8_t lz_buffer[ 4096 ];

	uint8_t *lzfu_data                = 0;
	uint8_t *lzfu_reference_data      = 0;
	static char *function             = "lzfu_decompress";
	size_t compressed_data_iterator   = 0;
	size_t uncompressed_data_iterator = 0;
	uint32_t calculated_crc           = 0;
	uint16_t lz_buffer_iterator       = 0;
	uint16_t reference_offset         = 0;
	uint16_t reference_size           = 0;
	uint16_t reference_iterator       = 0;
	uint8_t flag_byte_bit_mask        = 0;
	uint8_t flag_byte                 = 0;

	if( uncompressed_data == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid uncompressed data.",
		 function );

		return( -1 );
	}
	if( uncompressed_data_size == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid uncompressed data size.",
		 function );

		return( -1 );
	}
	if( compressed_data == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid compressed data.",
		 function );

		return( -1 );
	}
	if( compressed_data_size > (size_t) SSIZE_MAX )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
		 "%s: invalid compressed data size value exceeds maximum.",
		 function );

		return( -1 );
	}
	if( memory_copy(
	     lz_buffer,
	     lzfu_rtf_dictionary,
	     207 ) == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
		 "%s: unable to initialize lz buffer.",
		 function );

		return( -1 );
	}
	lz_buffer_iterator = 207;

	if( memory_set(
	     &( lz_buffer[ lz_buffer_iterator ] ),
	     0,
	     ( 4096 - lz_buffer_iterator ) ) == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
		 "%s: unable to clear lz buffer.",
		 function );

		return( -1 );
	}
	lzfu_data = compressed_data;

	byte_stream_copy_to_uint32_little_endian(
	 lzfu_data,
	 lzfu_header.compressed_data_size );

	lzfu_data += 4;

	byte_stream_copy_to_uint32_little_endian(
	 lzfu_data,
	 lzfu_header.uncompressed_data_size );

	lzfu_data += 4;

	byte_stream_copy_to_uint32_little_endian(
	 lzfu_data,
	 lzfu_header.signature );

	lzfu_data += 4;

	byte_stream_copy_to_uint32_little_endian(
	 lzfu_data,
	 lzfu_header.crc );

	lzfu_data += 4;

	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: lzfu header compressed data size\t: %" PRIu32 "\n",
		 function,
		 lzfu_header.compressed_data_size );

		libcnotify_printf(
		 "%s: lzfu header uncompressed data size\t: %" PRIu32 "\n",
		 function,
		 lzfu_header.uncompressed_data_size );

		libcnotify_printf(
		 "%s: lzfu header signature\t\t\t: 0x08%" PRIx32 "\n",
		 function,
		 lzfu_header.signature );

		libcnotify_printf(
		 "%s: lzfu header crc\t\t\t: %" PRIu32 "\n",
		 function,
		 lzfu_header.crc );
	}
	if( ( lzfu_header.signature != LZFU_SIGNATURE_COMPRESSED )
	 && ( lzfu_header.signature != LZFU_SIGNATURE_UNCOMPRESSED ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported compression signature: 0x%08" PRIx32 ".",
		 function,
		 lzfu_header.signature );

		return( -1 );
	}
	compressed_data_size -= sizeof( lzfu_header_t );

	/* The compressed data size includes 12 bytes of the header
	 */
	lzfu_header.compressed_data_size -= 12;

#ifdef X
	if( lzfu_header.compressed_data_size != compressed_data_size )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_RANGE,
		 "%s: mismatch in compressed data size (%" PRIu32 " != %" PRIzd ").",
		 function,
		 lzfu_header.compressed_data_size,
		 compressed_data_size );

		return( -1 );
	}
#endif
	/* Make sure the uncompressed buffer is large enough
	 */
	if( *uncompressed_data_size < lzfu_header.uncompressed_data_size )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
		 "%s: uncompressed data too small.",
		 function );

		*uncompressed_data_size = lzfu_header.uncompressed_data_size;

		return( -1 );
	}
	if( crc32_calculate(
	     &calculated_crc,
	     lzfu_data,
	     (size_t) lzfu_header.compressed_data_size,
	     0,
	     1,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
		 "%s: unable to calculate weak CRC.",
		 function );

		return( -1 );
	}
	if( lzfu_header.crc != calculated_crc )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_INPUT,
		 LIBCERROR_INPUT_ERROR_CHECKSUM_MISMATCH,
		 "%s: mismatch in crc ( %" PRIu32 " != %" PRIu32 " ).",
		 function,
		 lzfu_header.crc,
		 calculated_crc );

		return( -1 );
	}
	while( compressed_data_iterator < (size_t) lzfu_header.compressed_data_size )
	{
		flag_byte = lzfu_data[ compressed_data_iterator++ ];

		/* Check every bit in the chunk flag byte from LSB to MSB
		 */
		for( flag_byte_bit_mask = 0x01; flag_byte_bit_mask != 0x00; flag_byte_bit_mask <<= 1 )
		{
			if( compressed_data_iterator == (size_t) lzfu_header.compressed_data_size )
			{
				break;
			}
			/* Check if the byte value is a literal or a reference
			 */
			if( ( flag_byte & flag_byte_bit_mask ) == 0 )
			{
				if( compressed_data_iterator >= (size_t) lzfu_header.compressed_data_size )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
					 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
					 "%s: missing compressed data.",
					 function );

					*uncompressed_data_size = 0;

					return( -1 );
				}
				if( uncompressed_data_iterator >= *uncompressed_data_size )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
					 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
					 "%s: uncompressed data too small.",
					 function );

					*uncompressed_data_size = uncompressed_data_iterator;

					return( -1 );
				}
				lz_buffer[ lz_buffer_iterator++ ]                 = lzfu_data[ compressed_data_iterator ];
				uncompressed_data[ uncompressed_data_iterator++ ] = lzfu_data[ compressed_data_iterator ];

				compressed_data_iterator++;

				/* Make sure the lz buffer iterator wraps around
				 */
				lz_buffer_iterator %= 4096;

				lz_buffer[ lz_buffer_iterator ] = 0;
			}
			else
			{
				if( ( compressed_data_iterator + 1 ) >= (size_t) lzfu_header.compressed_data_size )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
					 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
					 "%s: missing compressed data.",
					 function );

					*uncompressed_data_size = 0;

					return( -1 );
				}
				lzfu_reference_data = &( lzfu_data[ compressed_data_iterator ] );

				compressed_data_iterator += 2;

				byte_stream_copy_to_uint16_big_endian(
				 lzfu_reference_data,
				 reference_offset );

				reference_size     = ( reference_offset & 0x000f ) + 2;
				reference_offset >>= 4;

				if( ( uncompressed_data_iterator + reference_size - 1 ) >= *uncompressed_data_size )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
					 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
					 "%s: uncompressed data too small.",
					 function );

					*uncompressed_data_size = uncompressed_data_iterator + reference_size;

					return( -1 );
				}
				for( reference_iterator = 0; reference_iterator < reference_size; reference_iterator++ )
				{
					lz_buffer[ lz_buffer_iterator++ ]                 = lz_buffer[ reference_offset ];
					uncompressed_data[ uncompressed_data_iterator++ ] = lz_buffer[ reference_offset ];

					reference_offset++;

					/* Make sure the lz buffer iterator and reference offset wrap around
					 */
					lz_buffer_iterator %= 4096;
					reference_offset   %= 4096;

					lz_buffer[ lz_buffer_iterator ] = 0;
				}
			}
		}
	}
	*uncompressed_data_size = uncompressed_data_iterator;

	return( 1 );
}
Example #5
0
/* Copies a byte stream from a base16 stream
 *
 * LIBUNA_BASE16_FLAG_STRIP_WHITESPACE removes leading space and tab characters,
 * and trailing space, tab and end of line characters
 *
 * Returns 1 if successful or -1 on error
 */
int libuna_base16_stream_copy_to_byte_stream(
     const uint8_t *base16_stream,
     size_t base16_stream_size,
     uint8_t *byte_stream,
     size_t byte_stream_size,
     uint32_t base16_variant,
     uint8_t flags,
     libcerror_error_t **error )
{
	static char *function        = "libuna_base16_stream_copy_to_byte_stream";
	size_t base16_character_size = 0;
	size_t base16_stream_index   = 0;
	size_t byte_stream_index     = 0;
	size_t number_of_characters  = 0;
	size_t whitespace_size       = 0;
	uint32_t base16_character1   = 0;
	uint32_t base16_character2   = 0;
	uint8_t byte_value           = 0;
	uint8_t character_case       = 0;
	uint8_t character_limit      = 0;
	uint8_t strip_mode           = LIBUNA_STRIP_MODE_LEADING_WHITESPACE;

	if( base16_stream == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid base16 stream.",
		 function );

		return( -1 );
	}
	if( base16_stream_size > (size_t) SSIZE_MAX )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
		 "%s: invalid base16 stream size value exceeds maximum.",
		 function );

		return( -1 );
	}
	if( byte_stream == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid byte stream.",
		 function );

		return( -1 );
	}
	if( byte_stream_size > (size_t) SSIZE_MAX )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
		 "%s: invalid byte stream size value exceeds maximum.",
		 function );

		return( -1 );
	}
	switch( base16_variant & 0x000000ffUL )
	{
		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_NONE:
			character_limit = 0;
			break;

		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_64:
			character_limit = 64;
			break;

		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_76:
			character_limit = 76;
			break;

		default:
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
			 "%s: unsupported base16 variant.",
			 function );

			return( -1 );
	}
	switch( base16_variant & 0x000f0000UL )
	{
		case LIBUNA_BASE16_VARIANT_CASE_LOWER:
			character_case = LIBUNA_CASE_LOWER;
			break;

		case LIBUNA_BASE16_VARIANT_CASE_MIXED:
			character_case = LIBUNA_CASE_MIXED;
			break;

		case LIBUNA_BASE16_VARIANT_CASE_UPPER:
			character_case = LIBUNA_CASE_UPPER;
			break;

		default:
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
			 "%s: unsupported base16 variant.",
			 function );

			return( -1 );
	}
	switch( base16_variant & 0xf0000000UL )
	{
		case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM:
			base16_character_size = 1;
			break;

		case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
		case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
			base16_character_size = 2;
			break;

		case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
		case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
			base16_character_size = 4;
			break;

		default:
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
			 "%s: unsupported base16 variant.",
			 function );

			return( -1 );
	}
	if( base16_stream_size < base16_character_size )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
		 "%s: invalid base16 stream value too small.",
		 function );

		return( -1 );
	}
	if( ( flags & ~( LIBUNA_BASE16_FLAG_STRIP_WHITESPACE ) ) != 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported flags.",
		 function );

		return( -1 );
	}
	if( ( flags & LIBUNA_BASE16_FLAG_STRIP_WHITESPACE ) == 0 )
	{
		strip_mode = LIBUNA_STRIP_MODE_NON_WHITESPACE;
	}
	base16_stream_index = base16_stream_size - base16_character_size;
	whitespace_size     = 0;

	while( base16_stream_index > base16_character_size )
	{
		switch( base16_variant & 0xf0000000UL )
		{
			case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM:
				base16_character1 = base16_stream[ base16_stream_index ];
				break;

			case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
				byte_stream_copy_to_uint16_big_endian(
				 &( base16_stream[ base16_stream_index ] ),
				 base16_character1 );
				break;

			case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
				byte_stream_copy_to_uint16_little_endian(
				 &( base16_stream[ base16_stream_index ] ),
				 base16_character1 );
				break;

			case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
				byte_stream_copy_to_uint32_big_endian(
				 &( base16_stream[ base16_stream_index ] ),
				 base16_character1 );
				break;

			case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
				byte_stream_copy_to_uint32_little_endian(
				 &( base16_stream[ base16_stream_index ] ),
				 base16_character1 );
				break;
		}
		if( ( base16_character1 & 0xffffff00UL ) != 0 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
			 "%s: invalid base16 character at index: %" PRIzd ".",
			 function,
			 base16_stream_index );

			return( -1 );
		}
		base16_stream_index -= base16_character_size;

		if( ( base16_character1 == (uint32_t) '\n' )
		 || ( base16_character1 == (uint32_t) '\r' ) )
		{
			whitespace_size += base16_character_size;
		}
		else if( ( flags & LIBUNA_BASE16_FLAG_STRIP_WHITESPACE ) == 0 )
		{
			break;
		}
		else if( ( base16_character1 == (uint32_t) ' ' )
		      || ( base16_character1 == (uint32_t) '\t' )
		      || ( base16_character1 == (uint32_t) '\v' ) )
		{
			whitespace_size += base16_character_size;
		}
		else
		{
			break;
		}
	}
	base16_stream_size -= whitespace_size;

	if( base16_stream_size < base16_character_size )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
		 "%s: invalid base16 stream value too small.",
		 function );

		return( -1 );
	}
	base16_stream_index = 0;

	while( base16_stream_index < base16_stream_size )
	{
		switch( base16_variant & 0xf0000000UL )
		{
			case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM:
				base16_character1 = base16_stream[ base16_stream_index ];
				break;

			case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
				byte_stream_copy_to_uint16_big_endian(
				 &( base16_stream[ base16_stream_index ] ),
				 base16_character1 );
				break;

			case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
				byte_stream_copy_to_uint16_little_endian(
				 &( base16_stream[ base16_stream_index ] ),
				 base16_character1 );
				break;

			case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
				byte_stream_copy_to_uint32_big_endian(
				 &( base16_stream[ base16_stream_index ] ),
				 base16_character1 );
				break;

			case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
				byte_stream_copy_to_uint32_little_endian(
				 &( base16_stream[ base16_stream_index ] ),
				 base16_character1 );
				break;
		}
		if( ( base16_character1 & 0xffffff00UL ) != 0 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
			 "%s: invalid base16 character at index: %" PRIzd ".",
			 base16_stream_index,
			 function );

			return( -1 );
		}
		base16_stream_index += base16_character_size;

		if( ( base16_character1 == (uint32_t) '\n' )
		 || ( base16_character1 == (uint32_t) '\r' ) )
		{
			if( ( strip_mode != LIBUNA_STRIP_MODE_NON_WHITESPACE )
			 && ( strip_mode != LIBUNA_STRIP_MODE_TRAILING_WHITESPACE ) )
			{
				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
			}
			else
			{
				if( ( base16_stream_index + base16_character_size ) < base16_stream_size )
				{
					switch( base16_variant & 0xf0000000UL )
					{
						case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM:
							base16_character2 = base16_stream[ base16_stream_index ];
							break;

						case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
							byte_stream_copy_to_uint16_big_endian(
							 &( base16_stream[ base16_stream_index ] ),
							 base16_character2 );
							break;

						case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
							byte_stream_copy_to_uint16_little_endian(
							 &( base16_stream[ base16_stream_index ] ),
							 base16_character2 );
							break;

						case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
							byte_stream_copy_to_uint32_big_endian(
							 &( base16_stream[ base16_stream_index ] ),
							 base16_character2 );
							break;

						case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
							byte_stream_copy_to_uint32_little_endian(
							 &( base16_stream[ base16_stream_index ] ),
							 base16_character2 );
							break;
					}
					if( ( base16_character2 & 0xffffff00UL ) != 0 )
					{
						libcerror_error_set(
						 error,
						 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
						 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
						 "%s: invalid base16 character at index: %" PRIzd ".",
						 function,
						 base16_stream_index );

						return( -1 );
					}
					if( ( base16_character2 == (uint32_t) '\n' )
					 || ( base16_character2 == (uint32_t) '\r' ) )
					{
						base16_stream_index += base16_character_size;
					}
				}
				strip_mode = LIBUNA_STRIP_MODE_LEADING_WHITESPACE;
			}
			if( character_limit != 0 )
			{
				if( number_of_characters != (size_t) character_limit )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_CONVERSION,
					 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
					 "%s: number of characters in line does not match character limit.",
					 function );

					return( -1 );
				}
				number_of_characters = 0;
			}
		}
		else if( ( base16_character1 == (uint32_t) ' ' )
		      || ( base16_character1 == (uint32_t) '\t' )
		      || ( base16_character1 == (uint32_t) '\v' ) )
		{
			if( ( flags & LIBUNA_BASE16_FLAG_STRIP_WHITESPACE ) != 0 )
			{
				if( strip_mode == LIBUNA_STRIP_MODE_NON_WHITESPACE )
				{
					strip_mode = LIBUNA_STRIP_MODE_TRAILING_WHITESPACE;
				}
				if( ( strip_mode != LIBUNA_STRIP_MODE_LEADING_WHITESPACE )
				 && ( strip_mode != LIBUNA_STRIP_MODE_TRAILING_WHITESPACE ) )
				{
					strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
				}
			}
			else
			{
				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
			}
		}
		else if( strip_mode == LIBUNA_STRIP_MODE_LEADING_WHITESPACE )
		{
			strip_mode = LIBUNA_STRIP_MODE_NON_WHITESPACE;
		}
		else if( strip_mode == LIBUNA_STRIP_MODE_TRAILING_WHITESPACE )
		{
			strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
		}
		if( strip_mode == LIBUNA_STRIP_MODE_INVALID_CHARACTER )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
			 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
			 "%s: invalid character in base16 stream at index: %" PRIzd ".",
			 function,
			 base16_stream_index - base16_character_size );

			return( -1 );
		}
		if( strip_mode == LIBUNA_STRIP_MODE_NON_WHITESPACE )
		{
			byte_value = 0;

			if( ( base16_character1 >= (uint32_t) 'A' )
			 && ( base16_character1 <= (uint32_t) 'F' ) )
			{
				if( ( character_case != LIBUNA_CASE_MIXED )
				 && ( character_case != LIBUNA_CASE_UPPER ) )
				{
					strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
				}
				byte_value = (uint8_t) ( base16_character1 - (uint32_t) 'A' + 10 );
			}
			else if( ( base16_character1 >= (uint32_t) 'a' )
			      && ( base16_character1 <= (uint32_t) 'f' ) )
			{
				if( ( character_case != LIBUNA_CASE_MIXED )
				 && ( character_case != LIBUNA_CASE_LOWER ) )
				{
					strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
				}
				byte_value = (uint8_t) ( base16_character1 - (uint32_t) 'a' + 10 );
			}
			else if( ( base16_character1 >= (uint32_t) '0' )
			      && ( base16_character1 <= (uint32_t) '9' ) )
			{
				byte_value = (uint8_t) ( base16_character1 - (uint32_t) '0' );
			}
			else
			{
				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
			}
			if( strip_mode == LIBUNA_STRIP_MODE_INVALID_CHARACTER )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
				 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
				 "%s: invalid base16 character stream at index: %" PRIzd ".",
				 function,
				 base16_stream_index - base16_character_size );

				return( -1 );
			}
			byte_value <<= 4;

			switch( base16_variant & 0xf0000000UL )
			{
				case LIBUNA_BASE16_VARIANT_ENCODING_BYTE_STREAM:
					base16_character1 = base16_stream[ base16_stream_index ];
					break;

				case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_BIG_ENDIAN:
					byte_stream_copy_to_uint16_big_endian(
					 &( base16_stream[ base16_stream_index ] ),
					 base16_character1 );
					break;

				case LIBUNA_BASE16_VARIANT_ENCODING_UTF16_LITTLE_ENDIAN:
					byte_stream_copy_to_uint16_little_endian(
					 &( base16_stream[ base16_stream_index ] ),
					 base16_character1 );
					break;

				case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_BIG_ENDIAN:
					byte_stream_copy_to_uint32_big_endian(
					 &( base16_stream[ base16_stream_index ] ),
					 base16_character1 );
					break;

				case LIBUNA_BASE16_VARIANT_ENCODING_UTF32_LITTLE_ENDIAN:
					byte_stream_copy_to_uint32_little_endian(
					 &( base16_stream[ base16_stream_index ] ),
					 base16_character1 );
					break;
			}
			if( ( base16_character1 & 0xffffff00UL ) != 0 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
				 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
				 "%s: invalid base16 character at index: %" PRIzd ".",
				 base16_stream_index,
				 function );

				return( -1 );
			}
			base16_stream_index += base16_character_size;

			if( ( base16_character1 >= (uint32_t) 'A' )
			 && ( base16_character1 <= (uint32_t) 'F' ) )
			{
				if( ( character_case != LIBUNA_CASE_MIXED )
				 && ( character_case != LIBUNA_CASE_UPPER ) )
				{
					strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
				}
				byte_value |= (uint8_t) ( base16_character1 - (uint32_t) 'A' + 10 );
			}
			else if( ( base16_character1 >= (uint32_t) 'a' )
			      && ( base16_character1 <= (uint32_t) 'f' ) )
			{
				if( ( character_case != LIBUNA_CASE_MIXED )
				 && ( character_case != LIBUNA_CASE_LOWER ) )
				{
					strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
				}
				byte_value |= (uint8_t) ( base16_character1 - (uint32_t) 'a' + 10 );
			}
			else if( ( base16_character1 >= (uint32_t) '0' )
			      && ( base16_character1 <= (uint32_t) '9' ) )
			{
				byte_value |= (uint8_t) ( base16_character1 - (uint32_t) '0' );
			}
			else
			{
				strip_mode = LIBUNA_STRIP_MODE_INVALID_CHARACTER;
			}
			if( strip_mode == LIBUNA_STRIP_MODE_INVALID_CHARACTER )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
				 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
				 "%s: invalid base16 character stream at index: %" PRIzd ".",
				 function,
				 base16_stream_index - base16_character_size );

				return( -1 );
			}
			if( byte_stream_index >= byte_stream_size )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
				 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
				 "%s: byte stream is too small.",
				 function );

				return( -1 );
			}
			byte_stream[ byte_stream_index++ ] = byte_value;

			number_of_characters += 2;
		}
	}
	if( character_limit != 0 )
	{
		if( number_of_characters > (size_t) character_limit )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
			 LIBCERROR_CONVERSION_ERROR_INPUT_FAILED,
			 "%s: number of characters in last line exceed maximum.",
			 function );

			return( -1 );
		}
	}
	return( 1 );
}
Example #6
0
/* Reads a B-tree file node descriptor
 * Returns 1 if successful or -1 on error
 */
int libfshfs_btree_file_read_node_descriptor(
     const uint8_t *data,
     size_t data_size,
     uint16_t *number_of_records,
     libcerror_error_t **error )
{
	static char *function         = "libfshfs_btree_file_read_node_descriptor";
	uint32_t next_node_number     = 0;
	uint32_t previous_node_number = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	uint16_t value_16bit          = 0;
#endif

	if( data == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: invalid data.",
		 function );

		return( -1 );
	}
	if( ( data_size < sizeof( fshfs_btree_node_descriptor_t ) )
	 || ( data_size > (size_t) SSIZE_MAX ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
		 "%s: invalid data size value out of bounds.",
		 function );

		return( -1 );
	}
	if( number_of_records == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: invalid number of records.",
		 function );

		return( -1 );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: B-tree node descriptor data:\n",
		 function );
		libcnotify_print_data(
		 (uint8_t *) data,
		 sizeof( fshfs_btree_node_descriptor_t ),
		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
	}
#endif
	byte_stream_copy_to_uint32_big_endian(
	 ( (fshfs_btree_node_descriptor_t *) data )->next_node_number,
	 next_node_number );

	byte_stream_copy_to_uint32_big_endian(
	 ( (fshfs_btree_node_descriptor_t *) data )->previous_node_number,
	 previous_node_number );

	byte_stream_copy_to_uint16_big_endian(
	 ( (fshfs_btree_node_descriptor_t *) data )->number_of_records,
	 *number_of_records );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: next node number\t\t: %" PRIu32 "\n",
		 function,
		 next_node_number );

		libcnotify_printf(
		 "%s: previous node number\t\t: %" PRIu32 "\n",
		 function,
		 previous_node_number );

		libcnotify_printf(
		 "%s: node type\t\t\t: %" PRIi8 " (%s)\n",
		 function,
		 ( (fshfs_btree_node_descriptor_t *) data )->node_type,
		 libfshfs_debug_print_btree_node_type(
		  ( (fshfs_btree_node_descriptor_t *) data )->node_type ) );

		libcnotify_printf(
		 "%s: node level\t\t\t: %" PRIi8 "\n",
		 function,
		 ( (fshfs_btree_node_descriptor_t *) data )->node_level );

		libcnotify_printf(
		 "%s: number of records\t\t: %" PRIu16 "\n",
		 function,
		 *number_of_records );

		byte_stream_copy_to_uint16_big_endian(
		 ( (fshfs_btree_node_descriptor_t *) data )->unknown1,
		 value_16bit );
		libcnotify_printf(
		 "%s: unknown1\t\t\t: 0x%04" PRIx16 "\n",
		 function,
		 value_16bit );

		libcnotify_printf(
		 "\n",
		 function );
	}
#endif
	return( 1 );
}
Example #7
0
/* Reads the B-tree file
 * Returns 1 if successful or -1 on error
 */
int libfshfs_btree_file_read(
     libfshfs_btree_file_t *btree_file,
     libfshfs_io_handle_t *io_handle,
     libbfio_handle_t *file_io_handle,
     libfshfs_fork_descriptor_t *fork_descriptor,
     libcerror_error_t **error )
{
	libfcache_cache_t *btree_nodes_cache                 = NULL;
	libfdata_vector_t *btree_nodes_vector                = NULL;
	libfshfs_allocation_block_t *allocation_block        = NULL;
	fshfs_btree_node_descriptor_t *btree_node_descriptor = NULL;
	static char *function                                = "libfshfs_btree_file_read";
	size_t btree_node_data_offset                        = 0;
	uint32_t next_node_number                            = 0;
	uint32_t previous_node_number                        = 0;
	uint16_t number_of_records                           = 0;
	uint16_t record_index                                = 0;
	uint16_t record_offset                               = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	uint16_t value_16bit                                 = 0;
	size_t btree_node_record_offsets_data_size           = 0;
#endif

	if( btree_file == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid B-tree file.",
		 function );

		return( -1 );
	}
	if( libfshfs_allocation_block_vector_initialize(
	     &btree_nodes_vector,
	     io_handle,
	     512,
	     fork_descriptor,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
		 "%s: unable to create B-tree nodes vector.",
		 function );

		goto on_error;
	}
/* TODO add max number of cache definition */
	if( libfcache_cache_initialize(
	     &btree_nodes_cache,
	     4,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
		 "%s: unable to create B-tree nodes cache.",
		 function );

		goto on_error;
	}
	if( libfdata_vector_get_element_value_by_index(
	     btree_nodes_vector,
	     (intptr_t *) file_io_handle,
	     btree_nodes_cache,
	     0,
	     (intptr_t **) &allocation_block,
	     0,
	     error ) == -1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve B-tree node: 0.",
		 function );

		goto on_error;
	}
	if( allocation_block == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: invalid allocation block: 0.",
		 function );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: B-tree node data:\n",
		 function );
		libcnotify_print_data(
		 (uint8_t *) allocation_block->data,
		 512,
		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
	}
#endif
	if( libfshfs_btree_file_read_node_descriptor(
	     allocation_block->data,
	     allocation_block->data_size,
	     &number_of_records,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_READ_FAILED,
		 "%s: unable to read B-tree node descriptor.",
		 function );

		goto on_error;
	}
/* TODO add bounds checks */
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		btree_node_record_offsets_data_size = ( number_of_records + 1 ) * 2;

		libcnotify_printf(
		 "%s: B-tree node record offsets data:\n",
		 function );
		libcnotify_print_data(
		 (uint8_t *) &( allocation_block->data[ 512 - btree_node_record_offsets_data_size ] ),
		 btree_node_record_offsets_data_size,
		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
	}
#endif
	btree_node_data_offset = 510;

	for( record_index = 0;
	     record_index < number_of_records;
	     record_index++ )
	{
		byte_stream_copy_to_uint16_big_endian(
		 &( ( allocation_block->data )[ btree_node_data_offset ] ),
		 record_offset );

		btree_node_data_offset -= 2;

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: record offset: %" PRIu16 "\t\t\t\t: 0x%04" PRIx16 "\n",
			 function,
			 record_index,
			 record_offset );
		}
#endif
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		byte_stream_copy_to_uint16_big_endian(
		 &( ( allocation_block->data )[ btree_node_data_offset ] ),
		 value_16bit );
		libcnotify_printf(
		 "%s: free space offset\t\t\t\t: 0x%04" PRIx16 "\n",
		 function,
		 value_16bit );
	}
#endif
	if( libfdata_vector_free(
	     &btree_nodes_vector,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
		 "%s: unable to free B-tree nodes vector.",
		 function );

		goto on_error;
	}
	if( libfcache_cache_free(
	     &btree_nodes_cache,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
		 "%s: unable to free B-tree nodes cache.",
		 function );

		goto on_error;
	}
	return( 1 );

on_error:
	if( btree_nodes_cache != NULL )
	{
		libfcache_cache_free(
		 &btree_nodes_cache,
		 NULL );
	}
	if( btree_nodes_vector != NULL )
	{
		libfdata_vector_free(
		 &btree_nodes_vector,
		 NULL );
	}
	return( -1 );
}
Example #8
0
/* Reads the file header
 * Returns 1 if successful or -1 on error
 */
int libqcow_io_handle_read_file_header(
     libqcow_io_handle_t *io_handle,
     libbfio_handle_t *file_io_handle,
     uint32_t *encryption_method,
     libcerror_error_t **error )
{
	uint8_t *file_header_data                  = NULL;
	static char *function                      = "libqcow_io_handle_read_file_header";
	size_t read_size                           = 512;
	ssize_t read_count                         = 0;
	uint64_t backing_filename_offset           = 0;
	uint32_t number_of_level1_table_references = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	uint64_t value_64bit                       = 0;
	uint32_t value_32bit                       = 0;
	uint16_t value_16bit                       = 0;
#endif

	if( io_handle == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid IO handle.",
		 function );

		return( -1 );
	}
	if( io_handle->backing_filename != NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
		 "%s: invalid IO handle - backing filename value already set.",
		 function );

		return( -1 );
	}
	if( encryption_method == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid encryption method.",
		 function );

		return( -1 );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: reading file header at offset: 0 (0x00000000)\n",
		 function );
	}
#endif
	if( libbfio_handle_seek_offset(
	     file_io_handle,
	     0,
	     SEEK_SET,
	     error ) == -1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_SEEK_FAILED,
		 "%s: unable to seek file header offset: 0.",
		 function );

		goto on_error;
	}
	file_header_data = (uint8_t *) memory_allocate(
	                                sizeof( uint8_t ) * read_size );

	if( file_header_data == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
		 "%s: unable to create file header data.",
		 function );

		goto on_error;
	}
	read_count = libbfio_handle_read_buffer(
	              file_io_handle,
	              file_header_data,
	              read_size,
	              error );

	if( read_count != (ssize_t) read_size )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_READ_FAILED,
		 "%s: unable to read file header.",
		 function );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: file header data:\n",
		 function );
		libcnotify_print_data(
		 file_header_data,
		 sizeof( qcow_file_header_v1_t ),
		 0 );
	}
#endif
	if( memory_compare(
	     ( (qcow_file_header_v1_t *) file_header_data )->signature,
	     qcow_file_signature,
	     4 ) != 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported file signature.",
		 function );

		goto on_error;
	}
	byte_stream_copy_to_uint32_big_endian(
	 ( (qcow_file_header_v1_t *) file_header_data )->format_version,
	 io_handle->format_version );

	byte_stream_copy_to_uint64_big_endian(
	 ( (qcow_file_header_v1_t *) file_header_data )->backing_filename_offset,
	 backing_filename_offset );

	byte_stream_copy_to_uint32_big_endian(
	 ( (qcow_file_header_v1_t *) file_header_data )->backing_filename_size,
	 io_handle->backing_filename_size );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		byte_stream_copy_to_uint32_big_endian(
		 ( (qcow_file_header_v1_t *) file_header_data )->signature,
		 value_32bit );
		libcnotify_printf(
		 "%s: signature\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		libcnotify_printf(
		 "%s: format version\t\t\t: %" PRIu32 "\n",
		 function,
		 io_handle->format_version );

		libcnotify_printf(
		 "%s: backing filename offset\t\t: %" PRIu32 "\n",
		 function,
		 backing_filename_offset );

		libcnotify_printf(
		 "%s: backing filename size\t\t: %" PRIu32 "\n",
		 function,
		 io_handle->backing_filename_size );
	}
#endif
	if( ( io_handle->format_version != 1 )
	 && ( io_handle->format_version != 2 )
	 && ( io_handle->format_version != 3 ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported format version: %" PRIu32 ".",
		 function,
		 io_handle->format_version );

		goto on_error;
	}
	if( io_handle->format_version == 1 )
	{
		byte_stream_copy_to_uint64_big_endian(
		 ( (qcow_file_header_v1_t *) file_header_data )->media_size,
		 io_handle->media_size );

		io_handle->number_of_cluster_block_bits = (uint32_t) ( (qcow_file_header_v1_t *) file_header_data )->number_of_cluster_block_bits;

		io_handle->number_of_level2_table_bits = (uint32_t) ( (qcow_file_header_v1_t *) file_header_data )->number_of_level2_table_bits;

		byte_stream_copy_to_uint32_big_endian(
		 ( (qcow_file_header_v1_t *) file_header_data )->encryption_method,
		 *encryption_method );

		byte_stream_copy_to_uint64_big_endian(
		 ( (qcow_file_header_v2_t *) file_header_data )->level1_table_offset,
		 io_handle->level1_table_offset );

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			byte_stream_copy_to_uint32_big_endian(
			 ( (qcow_file_header_v1_t *) file_header_data )->modification_time,
			 value_32bit );
			libcnotify_printf(
			 "%s: modification time\t\t\t: %" PRIu32 "\n",
			 function,
			 value_32bit );

			libcnotify_printf(
			 "%s: media size\t\t\t\t: %" PRIu64 "\n",
			 function,
			 io_handle->media_size );

			libcnotify_printf(
			 "%s: number of cluster block bits\t: %" PRIu32 "\n",
			 function,
			 io_handle->number_of_cluster_block_bits );

			libcnotify_printf(
			 "%s: number of level 2 table bits\t: %" PRIu32 "\n",
			 function,
			 io_handle->number_of_level2_table_bits );

			byte_stream_copy_to_uint16_big_endian(
			 ( (qcow_file_header_v1_t *) file_header_data )->unknown1,
			 value_16bit );
			libcnotify_printf(
			 "%s: unknown1\t\t\t\t: 0x%04" PRIx16 "\n",
			 function,
			 value_16bit );

			libcnotify_printf(
			 "%s: encryption method\t\t\t: %" PRIu32 "\n",
			 function,
			 *encryption_method );

			libcnotify_printf(
			 "%s: level 1 table offset\t\t: 0x%08" PRIx64 "\n",
			 function,
			 io_handle->level1_table_offset );
		}
#endif
	}
	else if( ( io_handle->format_version == 2 )
	      || ( io_handle->format_version == 3 ) )
	{
		byte_stream_copy_to_uint32_big_endian(
		 ( (qcow_file_header_v2_t *) file_header_data )->number_of_cluster_block_bits,
		 io_handle->number_of_cluster_block_bits );

		byte_stream_copy_to_uint32_big_endian(
		 ( (qcow_file_header_v2_t *) file_header_data )->number_of_level1_table_references,
		 number_of_level1_table_references );

		byte_stream_copy_to_uint64_big_endian(
		 ( (qcow_file_header_v2_t *) file_header_data )->level1_table_offset,
		 io_handle->level1_table_offset );

		byte_stream_copy_to_uint64_big_endian(
		 ( (qcow_file_header_v2_t *) file_header_data )->media_size,
		 io_handle->media_size );

		byte_stream_copy_to_uint32_big_endian(
		 ( (qcow_file_header_v2_t *) file_header_data )->encryption_method,
		 *encryption_method );

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: number of cluster block bits\t: %" PRIu32 "\n",
			 function,
			 io_handle->number_of_cluster_block_bits );

			libcnotify_printf(
			 "%s: media size\t\t\t\t: %" PRIu64 "\n",
			 function,
			 io_handle->media_size );

			libcnotify_printf(
			 "%s: encryption method\t\t\t: %" PRIu32 "\n",
			 function,
			 *encryption_method );

			libcnotify_printf(
			 "%s: number of level 1 table references\t: %" PRIu32 "\n",
			 function,
			 number_of_level1_table_references );

			libcnotify_printf(
			 "%s: level 1 table offset\t\t: 0x%08" PRIx64 "\n",
			 function,
			 io_handle->level1_table_offset );

			byte_stream_copy_to_uint64_big_endian(
			 ( (qcow_file_header_v2_t *) file_header_data )->reference_count_table_offset,
			 value_64bit );
			libcnotify_printf(
			 "%s: reference count table offset\t: 0x%08" PRIx64 "\n",
			 function,
			 value_64bit );

			byte_stream_copy_to_uint32_big_endian(
			 ( (qcow_file_header_v2_t *) file_header_data )->reference_count_table_clusters,
			 value_32bit );
			libcnotify_printf(
			 "%s: reference count table clusters\t: %" PRIu32 "\n",
			 function,
			 value_32bit );

			byte_stream_copy_to_uint32_big_endian(
			 ( (qcow_file_header_v2_t *) file_header_data )->number_of_snapshots,
			 value_32bit );
			libcnotify_printf(
			 "%s: number of snapshots\t\t\t: %" PRIu32 "\n",
			 function,
			 value_32bit );

			byte_stream_copy_to_uint64_big_endian(
			 ( (qcow_file_header_v2_t *) file_header_data )->snapshots_offset,
			 value_64bit );
			libcnotify_printf(
			 "%s: snapshots offset\t\t\t: 0x%08" PRIx64 "\n",
			 function,
			 value_64bit );
		}
#endif
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "\n" );
	}
#endif
	memory_free(
	 file_header_data );

	file_header_data = NULL;

	if( io_handle->format_version == 1 )
	{
		io_handle->offset_bit_mask           = 0x7fffffffffffffffULL;
		io_handle->compression_flag_bit_mask = (uint64_t) 1 << 63;
		io_handle->compression_bit_shift     = 63 - io_handle->number_of_cluster_block_bits;
	}
	else if( ( io_handle->format_version == 2 )
	      || ( io_handle->format_version == 3 ) )
	{
		if( io_handle->number_of_cluster_block_bits <= 8 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: invalid number of cluster block bits value out of bounds.",
			 function );

			goto on_error;
		}
		io_handle->number_of_level2_table_bits = io_handle->number_of_cluster_block_bits - 3;
		io_handle->offset_bit_mask             = 0x3fffffffffffffffULL;
		io_handle->compression_flag_bit_mask   = (uint64_t) 1 << 62;
		io_handle->compression_bit_shift       = 62 - ( io_handle->number_of_cluster_block_bits - 8 );
	}
	io_handle->level1_index_bit_shift = io_handle->number_of_cluster_block_bits
	                                  + io_handle->number_of_level2_table_bits;

	io_handle->level2_index_bit_mask  = ~( (uint64_t) -1 << io_handle->number_of_level2_table_bits );
	io_handle->cluster_block_bit_mask = ~( (uint64_t) -1 << io_handle->number_of_cluster_block_bits );
	io_handle->compression_bit_mask   = ~( (uint64_t) -1 << io_handle->compression_bit_shift );
	io_handle->level2_table_size      = (size_t) 1 << io_handle->number_of_level2_table_bits;
	io_handle->cluster_block_size     = (size_t) 1 << io_handle->number_of_cluster_block_bits;

	if( io_handle->format_version == 1 )
	{
		io_handle->level1_table_size = (uint32_t) ( io_handle->cluster_block_size * io_handle->level2_table_size );

		if( ( io_handle->media_size % io_handle->level1_table_size ) != 0 )
		{
			io_handle->level1_table_size = (uint32_t) ( ( io_handle->media_size / io_handle->level1_table_size ) + 1 );
		}
		else
		{
			io_handle->level1_table_size = (uint32_t) ( io_handle->media_size / io_handle->level1_table_size );
		}
	}
	else if( ( io_handle->format_version == 2 )
	      || ( io_handle->format_version == 3 ) )
	{
		io_handle->level1_table_size = number_of_level1_table_references;
	}
	io_handle->level1_table_size *= 8;
	io_handle->level2_table_size *= 8;

#if UINT32_MAX > SSIZE_MAX
	if( io_handle->level1_table_size > (uint32_t) SSIZE_MAX )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
		 "%s: invalid level 1 table size value exceeds maximum.",
		 function );

		goto on_error;
	}
#endif
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: level 1 table size\t\t\t: %" PRIzd "\n",
		 function,
		 io_handle->level1_table_size );

		libcnotify_printf(
		 "%s: level 2 table size\t\t\t: %" PRIzd "\n",
		 function,
		 io_handle->level2_table_size );

		libcnotify_printf(
		 "%s: cluster block size\t\t\t: %" PRIzd "\n",
		 function,
		 io_handle->cluster_block_size );
	}
#endif
	if( ( backing_filename_offset > 0 )
	 && ( io_handle->backing_filename_size > 0 ) )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: reading backing filename at offset: %" PRIu64 " (0x%08" PRIx64 ")\n",
			 function,
			 backing_filename_offset,
			 backing_filename_offset );
		}
#endif
		if( libbfio_handle_seek_offset(
		     file_io_handle,
		     backing_filename_offset,
		     SEEK_SET,
		     error ) == -1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_SEEK_FAILED,
			 "%s: unable to seek file header offset: %" PRIu64 ".",
			 function,
			 backing_filename_offset );

			goto on_error;
		}
		io_handle->backing_filename = (uint8_t *) memory_allocate(
		                                           sizeof( uint8_t ) * io_handle->backing_filename_size );

		if( io_handle->backing_filename == NULL )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_MEMORY,
			 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
			 "%s: unable to create backing filename.",
			 function );

			goto on_error;
		}
		read_count = libbfio_handle_read_buffer(
			      file_io_handle,
			      io_handle->backing_filename,
			      io_handle->backing_filename_size,
			      error );

		if( read_count != (ssize_t) io_handle->backing_filename_size )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read file header.",
			 function );

			goto on_error;
		}
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: backing filename data:\n",
			 function );
			libcnotify_print_data(
			 io_handle->backing_filename,
			 (size_t) io_handle->backing_filename_size,
			 0 );
		}
#endif
	}
	return( 1 );

on_error:
	if( io_handle->backing_filename != NULL )
	{
		memory_free(
		 io_handle->backing_filename );

		io_handle->backing_filename      = NULL;
		io_handle->backing_filename_size = 0;
	}
	if( file_header_data != NULL )
	{
		memory_free(
		 file_header_data );
	}
	return( -1 );
}
/* Retrieves the table of contents from the optical disk using the SCSI READ TOC command
 * Returns 1 if successful, 0 if not or -1 on error
 */
int libsmdev_optical_disc_get_table_of_contents_scsi(
     libcfile_file_t *device_file,
     libsmdev_internal_handle_t *internal_handle,
     libcerror_error_t **error )
{
	uint8_t track_info_data[ 64 ];

	uint8_t *toc_data            = NULL;
	uint8_t *toc_entries         = NULL;
	static char *function        = "libsmdev_optical_disc_get_table_of_contents_scsi";
	void *reallocation           = NULL;
	size_t toc_data_offset       = 0;
	size_t toc_data_size         = 0;
	ssize_t read_count           = 0;
	uint32_t lead_out_size       = 0;
	uint32_t lead_out_offset     = 0;
	uint32_t last_track_offset   = 0;
	uint32_t track_offset        = 0;
	uint32_t session_size        = 0;
	uint32_t session_offset      = 0;
	uint32_t next_session_offset = 0;
	uint16_t entry_index         = 0;
	uint8_t first_track_number   = 0;
	uint8_t last_track_number    = 0;
	uint8_t lead_out_index       = 0;
	uint8_t number_of_sessions   = 0;
	uint8_t session_index        = 0;
	uint8_t track_index          = 0;
	uint8_t track_number         = 0;
	uint8_t track_type           = 0;
	int result                   = 0;

	toc_data_size = 1024;

	toc_data = (uint8_t *) memory_allocate(
	                        sizeof( uint8_t ) * toc_data_size );

	if( toc_data == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
		 "%s: unable to create TOC data.",
		 function );

		goto on_error;
	}
	if( memory_set(
	     toc_data,
	     0,
	     sizeof( uint8_t ) * toc_data_size ) == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_SET_FAILED,
		 "%s: unable to clear TOC data.",
		 function );

		goto on_error;
	}
	read_count = libsmdev_scsi_read_toc(
	              device_file,
	              LIBSMDEV_SCSI_TOC_CDB_FORMAT_RAW_TOC,
	              toc_data,
	              toc_data_size,
	              error );

	if( read_count == -1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve TOC.",
		 function );

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			if( ( error != NULL )
			 && ( *error != NULL ) )
			{
				libcnotify_print_error_backtrace(
				 *error );
			}
		}
#endif
		libcerror_error_free(
		 error );

		byte_stream_copy_to_uint16_big_endian(
		 toc_data,
		 toc_data_size );

		if( toc_data_size > 1024 )
		{
			reallocation = memory_reallocate(
					toc_data,
					sizeof( uint8_t ) * toc_data_size );

			if( reallocation == NULL )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_MEMORY,
				 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
				 "%s: unable to resize TOC data.",
				 function );

				goto on_error;
			}
			toc_data = (uint8_t *) reallocation;

			read_count = libsmdev_scsi_read_toc(
			              device_file,
			              LIBSMDEV_SCSI_TOC_CDB_FORMAT_RAW_TOC,
			              toc_data,
			              toc_data_size,
			              error );

			if( read_count == -1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
				 "%s: unable to retrieve TOC.",
				 function );

#if defined( HAVE_DEBUG_OUTPUT )
				if( libcnotify_verbose != 0 )
				{
					if( ( error != NULL )
					 && ( *error != NULL ) )
					{
						libcnotify_print_error_backtrace(
						 *error );
					}
				}
#endif
				libcerror_error_free(
				 error );
			}
		}
	}
	toc_data_size = (size_t) read_count;

	if( toc_data_size > 4 )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: header:\n",
			 function );
			libcnotify_print_data(
			 toc_data,
			 4,
			 0 );
		}
#endif
		number_of_sessions = (uint16_t) toc_data[ 3 ];

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: number of sessions\t\t\t: %" PRIu8 "\n",
			 function,
			 number_of_sessions );

			libcnotify_printf(
			 "\n" );
		}
#endif
		toc_entries     = &( toc_data[ 4 ] );
		toc_data_offset = 4;

		while( toc_data_offset < (size_t) toc_data_size )
		{
#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: entry: %02" PRIu16 ":\n",
				 function,
				 entry_index );
				libcnotify_print_data(
				 toc_entries,
				 11,
				 0 );
			}
#endif
			if( toc_entries[ 3 ] <= 0x63 )
			{
				libsmdev_optical_disc_copy_msf_to_lba(
				 toc_entries[ 8 ],
				 toc_entries[ 9 ],
				 toc_entries[ 10 ],
				 track_offset );
			}
			else if( toc_entries[ 3 ] == 0xa0 )
			{
				first_track_number = toc_entries[ 8 ];
			}
			else if( toc_entries[ 3 ] == 0xa1 )
			{
				last_track_number = toc_entries[ 8 ];
			}
			else if( toc_entries[ 3 ] == 0xa2 )
			{
				libsmdev_optical_disc_copy_msf_to_lba(
				 toc_entries[ 8 ],
				 toc_entries[ 9 ],
				 toc_entries[ 10 ],
				 lead_out_offset );
			}
			else if( toc_entries[ 3 ] == 0xb0 )
			{
				libsmdev_optical_disc_copy_absolute_msf_to_lba(
				 toc_entries[ 4 ],
				 toc_entries[ 5 ],
				 toc_entries[ 6 ],
				 next_session_offset );
			}
#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				if( toc_entries[ 3 ] <= 0x63 )
				{
					libcnotify_printf(
					 "%s: session: %02" PRIu16 " track: %02" PRIu8 "\t\t\t: %02" PRIu8 ":%02" PRIu8 ".%02" PRIu8 " (offset: %" PRIu32 ")\n",
					 function,
					 toc_entries[ 0 ],
					 toc_entries[ 3 ],
					 toc_entries[ 4 ],
					 toc_entries[ 5 ],
					 toc_entries[ 6 ],
					 track_offset );
				}
				else if( toc_entries[ 3 ] == 0xa0 )
				{
					libcnotify_printf(
					 "%s: session: %02" PRIu8 " first track number\t: %" PRIu8 "\n",
					 function,
					 toc_entries[ 0 ],
					 first_track_number );
				}
				else if( toc_entries[ 3 ] == 0xa1 )
				{
					libcnotify_printf(
					 "%s: session: %02" PRIu8 " last track number\t\t: %" PRIu8 "\n",
					 function,
					 toc_entries[ 0 ],
					 last_track_number );
				}
				else if( toc_entries[ 3 ] == 0xa2 )
				{
					libcnotify_printf(
					 "%s: session: %02" PRIu8 " lead out\t\t\t: %02" PRIu8 ":%02" PRIu8 ".%02" PRIu8 " (offset: %" PRIu32 ")\n",
					 function,
					 toc_entries[ 0 ],
					 toc_entries[ 8 ],
					 toc_entries[ 9 ],
					 toc_entries[ 10 ],
					 lead_out_offset );
				}
				else if( toc_entries[ 3 ] == 0xb0 )
				{
					libcnotify_printf(
					 "%s: session: %02" PRIu16 " end\t\t\t: %02" PRIu8 ":%02" PRIu8 ".%02" PRIu8 " (offset: %" PRIu32 ")\n",
					 function,
					 toc_entries[ 0 ],
					 toc_entries[ 4 ],
					 toc_entries[ 5 ],
					 toc_entries[ 6 ],
					 next_session_offset );
				}
				libcnotify_printf(
				 "\n" );
			}
#endif
			if( ( toc_entries[ 3 ] <= 0x63 )
			 || ( toc_entries[ 3 ] == 0xb0 ) )
			{
				if( track_number >= first_track_number )
				{
			 		if( toc_entries[ 3 ] == 0xb0 )
					{
						track_offset = lead_out_offset;
					}
					if( track_offset < last_track_offset )
					{
						libcerror_error_set(
						 error,
						 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
						 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
						 "%s: invalid track offset value out of bounds.",
						 function );

						goto on_error;
					}
					if( ( track_index + 1 ) != track_number )
					{
						libcerror_error_set(
						 error,
						 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
						 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
						 "%s: invalid track number value out of bounds.",
						 function );

						goto on_error;
					}
			 		if( toc_entries[ 3 ] == 0xa2 )
					{
						if( track_number != last_track_number )
						{
							libcerror_error_set(
							 error,
							 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
							 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
							 "%s: invalid track number value out of bounds.",
							 function );

							goto on_error;
						}
					}
					if( memory_set(
					     track_info_data,
					     0,
					     64 ) == NULL )
					{
						libcerror_error_set(
						 error,
						 LIBCERROR_ERROR_DOMAIN_MEMORY,
						 LIBCERROR_MEMORY_ERROR_SET_FAILED,
						 "%s: unable to clear track info data.",
						 function );

						goto on_error;
					}
					read_count = libsmdev_scsi_read_track_information(
					              device_file,
					              last_track_offset,
					              track_info_data,
					              64,
					              error );

					if( read_count == -1 )
					{
						libcerror_error_set(
						 error,
						 LIBCERROR_ERROR_DOMAIN_RUNTIME,
						 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
						 "%s: unable to retrieve track info data: %d.",
						 function,
						 track_index );

#if defined( HAVE_DEBUG_OUTPUT )
						if( libcnotify_verbose != 0 )
						{
							if( ( error != NULL )
							 && ( *error != NULL ) )
							{
								libcnotify_print_error_backtrace(
								 *error );
							}
						}
#endif
						libcerror_error_free(
						 error );

						break;
					}
#if defined( HAVE_DEBUG_OUTPUT )
					if( libcnotify_verbose != 0 )
					{
						libcnotify_printf(
						 "%s: track information data: %d:\n",
						 function,
						 track_index );
						libcnotify_print_data(
						 track_info_data,
						 (size_t) read_count,
						 0 );
					}
#endif
					if( track_info_data[ 2 ] != toc_entries[ 0 ] )
					{
						libcerror_error_set(
						 error,
						 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
						 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
						 "%s: invalid track information data - session number value out of bounds.",
						 function );

						goto on_error;
					}
					if( track_info_data[ 3 ] != track_number )
					{
						libcerror_error_set(
						 error,
						 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
						 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
						 "%s: invalid track information data - track number value out of bounds.",
						 function );

						goto on_error;
					}
					track_type = LIBSMDEV_TRACK_TYPE_UNKNOWN;

					if( ( track_info_data[ 5 ] & 0x04 ) != 0 )
					{
						if( ( track_info_data[ 5 ] & 0x08 ) == 0 )
						{
							if( ( track_info_data[ 6 ] & 0x0f ) == 1 )
							{
								track_type = LIBSMDEV_TRACK_TYPE_MODE1_2048;
							}
							else if( ( track_info_data[ 6 ] & 0x0f ) == 2 )
							{
								track_type = LIBSMDEV_TRACK_TYPE_MODE2_2048;
							}
						}
					}
					else
					{
						track_type = LIBSMDEV_TRACK_TYPE_AUDIO;
					}
					if( libsmdev_handle_append_track(
					     internal_handle,
					     last_track_offset,
					     track_offset - last_track_offset,
					     track_type,
					     error ) != 1 )
					{
						libcerror_error_set(
						 error,
						 LIBCERROR_ERROR_DOMAIN_RUNTIME,
						 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
						 "%s: unable to append track: %d.",
						 function,
						 track_index );

						goto on_error;
					}
					track_index++;
				}
				last_track_offset = track_offset;

			 	if( toc_entries[ 3 ] != 0xb0 )
				{
					track_number = toc_entries[ 3 ];
				}
			}
			if( toc_entries[ 3 ] == 0xb0 )
			{
				if( session_offset >= next_session_offset )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
					 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
					 "%s: invalid session offset value out of bounds.",
					 function );

					goto on_error;
				}
				if( ( session_index + 1 ) != toc_entries[ 0 ] )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
					 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
					 "%s: invalid session number value out of bounds.",
					 function );

					goto on_error;
				}
				lead_out_size = 0;

				if( ( lead_out_offset >= session_offset )
				 && ( lead_out_offset < next_session_offset ) )
				{
					lead_out_size = next_session_offset - lead_out_offset;

					if( libsmdev_handle_append_lead_out(
					     internal_handle,
					     lead_out_offset,
					     lead_out_size,
					     error ) != 1 )
					{
						libcerror_error_set(
						 error,
						 LIBCERROR_ERROR_DOMAIN_RUNTIME,
						 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
						 "%s: unable to append lead_out: %d.",
						 function,
						 lead_out_index );

						goto on_error;
					}
					lead_out_index++;
				}
				session_size = next_session_offset - session_offset;

				if( ( session_index + 1 ) == number_of_sessions )
				{
					session_size -= lead_out_size;
				}
				if( libsmdev_handle_append_session(
				     internal_handle,
				     session_offset,
				     session_size,
				     error ) != 1 )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
					 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
					 "%s: unable to append session: %d.",
					 function,
					 session_index );

					goto on_error;
				}
				session_offset = next_session_offset;

				session_index++;
			}
			toc_entries     += 11;
			toc_data_offset += 11;

			entry_index++;
		}
		if( ( track_index + 1 ) == track_number )
		{
			if( track_offset < last_track_offset )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
				 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
				 "%s: invalid track offset value out of bounds.",
				 function );

				goto on_error;
			}
			if( memory_set(
			     track_info_data,
			     0,
			     64 ) == NULL )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_MEMORY,
				 LIBCERROR_MEMORY_ERROR_SET_FAILED,
				 "%s: unable to clear track info data.",
				 function );

				goto on_error;
			}
			read_count = libsmdev_scsi_read_track_information(
			              device_file,
			              last_track_offset,
			              track_info_data,
			              64,
			              error );

			if( read_count == -1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
				 "%s: unable to retrieve track info data: %d.",
				 function,
				 track_index );

#if defined( HAVE_DEBUG_OUTPUT )
				if( libcnotify_verbose != 0 )
				{
					if( ( error != NULL )
					 && ( *error != NULL ) )
					{
						libcnotify_print_error_backtrace(
						 *error );
					}
				}
#endif
				libcerror_error_free(
				 error );
			}
			else
			{
#if defined( HAVE_DEBUG_OUTPUT )
				if( libcnotify_verbose != 0 )
				{
					libcnotify_printf(
					 "%s: track information data: %d:\n",
					 function,
					 track_index );
					libcnotify_print_data(
					 track_info_data,
					 (size_t) read_count,
					 0 );
				}
#endif
				if( track_info_data[ 2 ] != toc_entries[ 0 ] )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
					 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
					 "%s: invalid track information data - session number value out of bounds.",
					 function );

					goto on_error;
				}
				if( track_info_data[ 3 ] != toc_entries[ 3 ] )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
					 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
					 "%s: invalid track information data - track number value out of bounds.",
					 function );

					goto on_error;
				}
				track_type = LIBSMDEV_TRACK_TYPE_UNKNOWN;

				if( ( track_info_data[ 5 ] & 0x04 ) != 0 )
				{
					if( ( track_info_data[ 5 ] & 0x08 ) == 0 )
					{
						if( ( track_info_data[ 6 ] & 0x0f ) == 1 )
						{
							track_type = LIBSMDEV_TRACK_TYPE_MODE1_2048;
						}
						else if( ( track_info_data[ 6 ] & 0x0f ) == 2 )
						{
							track_type = LIBSMDEV_TRACK_TYPE_MODE2_2048;
						}
					}
				}
				else
				{
					track_type = LIBSMDEV_TRACK_TYPE_AUDIO;
				}
				if( libsmdev_handle_append_track(
				     internal_handle,
				     last_track_offset,
				     track_offset - last_track_offset,
				     track_type,
				     error ) != 1 )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
					 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
					 "%s: unable to append last track: %d.",
					 function,
					 track_index );

					goto on_error;
				}
			}
			if( session_index != number_of_sessions )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
				 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
				 "%s: invalid session index value out of bounds.",
				 function );

				goto on_error;
			}
			result = 1;
		}
	}
	if( result == 0 )
	{
		if( libcdata_array_empty(
		     internal_handle->tracks_array,
		     (int (*)(intptr_t **, libcerror_error_t **)) &libsmdev_track_value_free,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
			 "%s: unable to empty tracks array.",
			 function );

			goto on_error;
		}
		if( libcdata_array_empty(
		     internal_handle->lead_outs_array,
		     (int (*)(intptr_t **, libcerror_error_t **)) &libsmdev_sector_range_free,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
			 "%s: unable to empty lead outs array.",
			 function );

			goto on_error;
		}
		if( libcdata_array_empty(
		     internal_handle->sessions_array,
		     (int (*)(intptr_t **, libcerror_error_t **)) &libsmdev_sector_range_free,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
			 "%s: unable to empty sessions array.",
			 function );

			goto on_error;
		}
	}
	memory_free(
	 toc_data );

	toc_data = NULL;

	return( result );

on_error:
	if( toc_data != NULL )
	{
		memory_free(
		 toc_data );
	}
	libcdata_array_empty(
	 internal_handle->tracks_array,
	 (int (*)(intptr_t **, libcerror_error_t **)) &libsmdev_track_value_free,
	 NULL );

	libcdata_array_empty(
	 internal_handle->lead_outs_array,
	 (int (*)(intptr_t **, libcerror_error_t **)) &libsmdev_sector_range_free,
	 NULL );

	libcdata_array_empty(
	 internal_handle->sessions_array,
	 (int (*)(intptr_t **, libcerror_error_t **)) &libsmdev_sector_range_free,
	 NULL );

	return( -1 );
}