/* Reads the URL values from an URL record
 * Returns 1 if successful or -1 on error
 */
int libmsiecf_url_values_read(
     libmsiecf_url_values_t *url_values,
     libmsiecf_io_handle_t *io_handle,
     libbfio_handle_t *file_io_handle,
     off64_t url_record_offset,
     size32_t record_size,
     uint8_t item_flags,
     libcerror_error_t **error )
{
	uint8_t *url_record_data                    = NULL;
	static char *function                       = "libmsiecf_url_values_read";
	ssize_t read_count                          = 0;
	ssize_t value_size                          = 0;
	uint32_t data_offset                        = 0;
	uint32_t data_size                          = 0;
	uint32_t filename_offset                    = 0;
	uint32_t location_offset                    = 0;
	uint32_t cache_entry_flags                  = 0;
	uint32_t unknown_offset                     = 0;
	uint16_t first_year                         = 0;
	uint16_t second_year                        = 0;
	uint8_t first_day_of_month                  = 0;
	uint8_t first_month                         = 0;
	uint8_t number_of_days                      = 0;
	uint8_t second_day_of_month                 = 0;
	uint8_t second_month                        = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	system_character_t date_time_string[ 32 ];

	libfdatetime_filetime_t *filetime           = NULL;
	libfdatetime_fat_date_time_t *fat_date_time = NULL;
	uint8_t *visited_entry_data                 = NULL;
	size_t string_index                         = 0;
	uint32_t value_32bit                        = 0;
	uint16_t value_16bit                        = 0;
	int result                                  = 0;
	int visited_entry_index                     = 0;
#endif

	if( url_values == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid URL values.",
		 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 );
	}
	if( file_io_handle == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid file IO handle.",
		 function );

		return( -1 );
	}
	if( record_size == 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
		 "%s: invalid record size value zero or less.",
		 function );

		return( -1 );
	}
#if SIZEOF_SIZE_T <= 4
	if( record_size > (size32_t) SSIZE_MAX )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
		 "%s: invalid record size value exceeds maximum.",
		 function );

		return( -1 );
	}
#endif
	if( ( record_size % 8 ) != 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported URL record size.",
		 function );

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

		goto on_error;
	}
	/* Add one block for tainted records
	 */
	if( ( item_flags & LIBMSIECF_ITEM_FLAG_TAINTED ) != 0 )
	{
		record_size += LIBMSIECF_DEFAULT_BLOCK_SIZE;
	}
	url_record_data = (uint8_t *) memory_allocate(
	                               record_size );

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

		goto on_error;
	}
	read_count = libbfio_handle_read_buffer(
	              file_io_handle,
	              url_record_data,
	              record_size,
	              error );

	if( read_count != (ssize_t) record_size )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_READ_FAILED,
		 "%s: unable to read URL record data.",
		 function );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: URL record data:\n",
		 function );
		libcnotify_print_data(
		 url_record_data,
		 record_size,
		 0 );
	}
#endif
	if( memory_compare(
	     url_record_data,
	     "URL ",
	     4 ) != 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported signature.",
		 function );

		goto on_error;
	}
	if( ( io_handle->major_version == 4 )
	 && ( io_handle->minor_version == 7 ) )
	{
		byte_stream_copy_to_uint64_little_endian(
		 ( (msiecf_url_record_header_v47_t *) url_record_data )->secondary_filetime,
		 url_values->secondary_time );

		byte_stream_copy_to_uint64_little_endian(
		 ( (msiecf_url_record_header_v47_t *) url_record_data )->primary_filetime,
		 url_values->primary_time );

		byte_stream_copy_to_uint64_little_endian(
		 ( (msiecf_url_record_header_v47_t *) url_record_data )->expiration_time,
		 url_values->expiration_time );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v47_t *) url_record_data )->cached_file_size,
		 url_values->cached_file_size );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v47_t *) url_record_data )->unknown_offset,
		 unknown_offset );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v47_t *) url_record_data )->location_offset,
		 location_offset );

		url_values->cache_directory_index = ( (msiecf_url_record_header_v47_t *) url_record_data )->cache_directory_index;

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v47_t *) url_record_data )->filename_offset,
		 filename_offset );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v47_t *) url_record_data )->data_offset,
		 data_offset );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v47_t *) url_record_data )->data_size,
		 data_size );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v47_t *) url_record_data )->last_checked_time,
		 url_values->last_checked_time );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v47_t *) url_record_data )->number_of_hits,
		 url_values->number_of_hits );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v47_t *) url_record_data )->cache_entry_flags,
		 cache_entry_flags );
	}
	else if( ( io_handle->major_version == 5 )
	      && ( io_handle->minor_version == 2 ) )
	{
		byte_stream_copy_to_uint64_little_endian(
		 ( (msiecf_url_record_header_v52_t *) url_record_data )->secondary_filetime,
		 url_values->secondary_time );

		byte_stream_copy_to_uint64_little_endian(
		 ( (msiecf_url_record_header_v52_t *) url_record_data )->primary_filetime,
		 url_values->primary_time );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v52_t *) url_record_data )->expiration_time,
		 url_values->expiration_time );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v52_t *) url_record_data )->cached_file_size,
		 url_values->cached_file_size );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v52_t *) url_record_data )->unknown_offset,
		 unknown_offset );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v52_t *) url_record_data )->location_offset,
		 location_offset );

		url_values->cache_directory_index = ( (msiecf_url_record_header_v52_t *) url_record_data )->cache_directory_index;

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v52_t *) url_record_data )->filename_offset,
		 filename_offset );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v52_t *) url_record_data )->data_offset,
		 data_offset );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v52_t *) url_record_data )->data_size,
		 data_size );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v52_t *) url_record_data )->last_checked_time,
		 url_values->last_checked_time );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v52_t *) url_record_data )->number_of_hits,
		 url_values->number_of_hits );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v52_t *) url_record_data )->cache_entry_flags,
		 cache_entry_flags );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		if( libfdatetime_fat_date_time_initialize(
		     &fat_date_time,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
			 "%s: unable to create FAT date time.",
			 function );

			goto on_error;
		}
		if( libfdatetime_filetime_initialize(
		     &filetime,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
			 "%s: unable to create filetime.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "%s: signature\t\t\t\t\t: %c%c%c%c\n",
		 function,
		 url_record_data[ 0 ],
		 url_record_data[ 1 ],
		 url_record_data[ 2 ],
		 url_record_data[ 3 ] );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_url_record_header_v47_t *) url_record_data )->number_of_blocks,
		 value_32bit );
		libcnotify_printf(
		 "%s: number of blocks\t\t\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		if( libfdatetime_filetime_copy_from_byte_stream(
		     filetime,
		     ( (msiecf_url_record_header_v47_t *) url_record_data )->secondary_filetime,
		     8,
		     LIBFDATETIME_ENDIAN_LITTLE,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
			 "%s: unable to copy filetime from byte stream.",
			 function );

			goto on_error;
		}
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
		result = libfdatetime_filetime_copy_to_utf16_string(
		          filetime,
		          (uint16_t *) date_time_string,
		          32,
		          LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
		          error );
#else
		result = libfdatetime_filetime_copy_to_utf8_string(
		          filetime,
		          (uint8_t *) date_time_string,
		          32,
		          LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
		          error );
#endif
		if( result != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
			 "%s: unable to copy filetime to date time string.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "%s: secondary time\t\t\t\t: %" PRIs_SYSTEM "\n",
		 function,
		 date_time_string );

		if( libfdatetime_filetime_copy_from_byte_stream(
		     filetime,
		     ( (msiecf_url_record_header_v47_t *) url_record_data )->primary_filetime,
		     8,
		     LIBFDATETIME_ENDIAN_LITTLE,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
			 "%s: unable to copy filetime from byte stream.",
			 function );

			goto on_error;
		}
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
		result = libfdatetime_filetime_copy_to_utf16_string(
		          filetime,
		          (uint16_t *) date_time_string,
		          32,
		          LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
		          error );
#else
		result = libfdatetime_filetime_copy_to_utf8_string(
		          filetime,
		          (uint8_t *) date_time_string,
		          32,
		          LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
		          error );
#endif
		if( result != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
			 "%s: unable to copy filetime to date time string.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "%s: primary time\t\t\t\t\t: %" PRIs_SYSTEM "\n",
		 function,
		 date_time_string );

		if( ( io_handle->major_version == 4 )
		 && ( io_handle->minor_version == 7 ) )
		{
			if( libfdatetime_filetime_copy_from_byte_stream(
			     filetime,
			     ( (msiecf_url_record_header_v47_t *) url_record_data )->expiration_time,
			     8,
			     LIBFDATETIME_ENDIAN_LITTLE,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
				 "%s: unable to copy filetime from byte stream.",
				 function );

				goto on_error;
			}
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
			result = libfdatetime_filetime_copy_to_utf16_string(
				  filetime,
				  (uint16_t *) date_time_string,
				  32,
				  LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
				  error );
#else
			result = libfdatetime_filetime_copy_to_utf8_string(
				  filetime,
				  (uint8_t *) date_time_string,
				  32,
				  LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
				  error );
#endif
			if( result != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
				 "%s: unable to copy filetime to date time string.",
				 function );

				goto on_error;
			}
		}
		else if( ( io_handle->major_version == 5 )
		      && ( io_handle->minor_version == 2 ) )
		{
			if( libfdatetime_fat_date_time_copy_from_byte_stream(
			     fat_date_time,
			     ( (msiecf_url_record_header_v52_t *) url_record_data )->expiration_time,
			     4,
			     LIBFDATETIME_ENDIAN_LITTLE,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_CONVERSION,
				 LIBCERROR_CONVERSION_ERROR_GENERIC,
				 "%s: unable to copy FAT date time from byte stream.",
				 function );

				goto on_error;
			}
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
			result = libfdatetime_fat_date_time_copy_to_utf16_string(
				  fat_date_time,
				  (uint16_t *) date_time_string,
				  32,
				  LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
				  LIBFDATETIME_DATE_TIME_FORMAT_CTIME,
				  error );
#else
			result = libfdatetime_fat_date_time_copy_to_utf8_string(
				  fat_date_time,
				  (uint8_t *) date_time_string,
				  32,
				  LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
				  error );
#endif
			if( result != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_CONVERSION,
				 LIBCERROR_CONVERSION_ERROR_GENERIC,
				 "%s: unable to copy FAT date time to date time string.",
				 function );

				goto on_error;
			}
		}
		libcnotify_printf(
		 "%s: expiration time\t\t\t\t: %" PRIs_SYSTEM "\n",
		 function,
		 date_time_string );

		if( ( io_handle->major_version == 5 )
		 && ( io_handle->minor_version == 2 ) )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (msiecf_url_record_header_v52_t *) url_record_data )->unknown1,
			 value_32bit );

			libcnotify_printf(
			 "%s: unknown1\t\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );
		}
		libcnotify_printf(
		 "%s: cached file size\t\t\t\t: %" PRIu32 " bytes\n",
		 function,
		 url_values->cached_file_size );

		if( ( io_handle->major_version == 4 )
		 && ( io_handle->minor_version == 7 ) )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (msiecf_url_record_header_v47_t *) url_record_data )->unknown1,
			 value_32bit );

			libcnotify_printf(
			 "%s: unknown1\t\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );
		}
		if( ( io_handle->major_version == 4 )
		 && ( io_handle->minor_version == 7 ) )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (msiecf_url_record_header_v47_t *) url_record_data )->unknown3,
			 value_32bit );
		}
		else if( ( io_handle->major_version == 5 )
		      && ( io_handle->minor_version == 2 ) )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (msiecf_url_record_header_v52_t *) url_record_data )->unknown3,
			 value_32bit );
		}
		libcnotify_printf(
		 "%s: unknown3\t\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		if( ( io_handle->major_version == 4 )
		 && ( io_handle->minor_version == 7 ) )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (msiecf_url_record_header_v47_t *) url_record_data )->unknown4,
			 value_32bit );
		}
		else if( ( io_handle->major_version == 5 )
		      && ( io_handle->minor_version == 2 ) )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (msiecf_url_record_header_v52_t *) url_record_data )->unknown4,
			 value_32bit );
		}
		libcnotify_printf(
		 "%s: unknown4\t\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		if( ( io_handle->major_version == 4 )
		 && ( io_handle->minor_version == 7 ) )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (msiecf_url_record_header_v47_t *) url_record_data )->non_releasable_time_delta,
			 value_32bit );
		}
		else if( ( io_handle->major_version == 5 )
		      && ( io_handle->minor_version == 2 ) )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (msiecf_url_record_header_v52_t *) url_record_data )->non_releasable_time_delta,
			 value_32bit );
		}
		libcnotify_printf(
		 "%s: non-releasable time delta\t\t\t: %" PRIu32 " seconds\n",
		 function,
		 value_32bit );

		libcnotify_printf(
		 "%s: unknown offset\t\t\t\t: %" PRIu32 "\n",
		 function,
		 unknown_offset );

		libcnotify_printf(
		 "%s: location offset\t\t\t\t: %" PRIu32 "\n",
		 function,
		 location_offset );

		libcnotify_printf(
		 "%s: cache directory index\t\t\t: %" PRIu8 "\n",
		 function,
		 url_values->cache_directory_index );

		if( ( io_handle->major_version == 4 )
		 && ( io_handle->minor_version == 7 ) )
		{
			libcnotify_printf(
			 "%s: unknown6\t\t\t\t\t: 0x%02" PRIx8 " 0x%02" PRIx8 " 0x%02" PRIx8 "\n",
			 function,
			 ( (msiecf_url_record_header_v47_t *) url_record_data )->unknown6[ 0 ],
			 ( (msiecf_url_record_header_v47_t *) url_record_data )->unknown6[ 1 ],
			 ( (msiecf_url_record_header_v47_t *) url_record_data )->unknown6[ 2 ] );
		}
		else if( ( io_handle->major_version == 5 )
		      && ( io_handle->minor_version == 2 ) )
		{
			libcnotify_printf(
			 "%s: unknown6\t\t\t\t\t: 0x%02" PRIx8 " 0x%02" PRIx8 " 0x%02" PRIx8 "\n",
			 function,
			 ( (msiecf_url_record_header_v52_t *) url_record_data )->unknown6[ 0 ],
			 ( (msiecf_url_record_header_v52_t *) url_record_data )->unknown6[ 1 ],
			 ( (msiecf_url_record_header_v52_t *) url_record_data )->unknown6[ 2 ] );
		}
		libcnotify_printf(
		 "%s: filename offset\t\t\t\t: %" PRIu32 "\n",
		 function,
		 filename_offset );

		libcnotify_printf(
		 "%s: cache entry flags\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 cache_entry_flags );
		libmsiecf_debug_print_cache_entry_flags(
		 cache_entry_flags );
		libcnotify_printf(
		 "\n" );

		libcnotify_printf(
		 "%s: data offset\t\t\t\t\t: %" PRIu32 "\n",
		 function,
		 data_offset );
		libcnotify_printf(
		 "%s: data size\t\t\t\t\t: %" PRIu32 "\n",
		 function,
		 data_size );

		if( ( io_handle->major_version == 4 )
		 && ( io_handle->minor_version == 7 ) )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (msiecf_url_record_header_v47_t *) url_record_data )->unknown8,
			 value_32bit );
		}
		else if( ( io_handle->major_version == 5 )
		      && ( io_handle->minor_version == 2 ) )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (msiecf_url_record_header_v52_t *) url_record_data )->unknown8,
			 value_32bit );
		}
		libcnotify_printf(
		 "%s: unknown8\t\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		if( ( io_handle->major_version == 4 )
		 && ( io_handle->minor_version == 7 ) )
		{
			result = libfdatetime_fat_date_time_copy_from_byte_stream(
			          fat_date_time,
			          ( (msiecf_url_record_header_v47_t *) url_record_data )->last_checked_time,
			          4,
			          LIBFDATETIME_ENDIAN_LITTLE,
			          error );
		}
		else if( ( io_handle->major_version == 5 )
		      && ( io_handle->minor_version == 2 ) )
		{
			result = libfdatetime_fat_date_time_copy_from_byte_stream(
			          fat_date_time,
			          ( (msiecf_url_record_header_v52_t *) url_record_data )->last_checked_time,
			          4,
			          LIBFDATETIME_ENDIAN_LITTLE,
			          error );
		}
		if( result != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
			 LIBCERROR_CONVERSION_ERROR_GENERIC,
			 "%s: unable to copy FAT date time from byte stream.",
			 function );

			goto on_error;
		}
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
		result = libfdatetime_fat_date_time_copy_to_utf16_string(
		          fat_date_time,
		          (uint16_t *) date_time_string,
		          32,
		          LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
		          error );
#else
		result = libfdatetime_fat_date_time_copy_to_utf8_string(
		          fat_date_time,
		          (uint8_t *) date_time_string,
		          32,
		          LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
		          error );
#endif
		if( result != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
			 LIBCERROR_CONVERSION_ERROR_GENERIC,
			 "%s: unable to copy FAT date time to date time string.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "%s: last checked time\t\t\t\t: %" PRIs_SYSTEM "\n",
		 function,
		 date_time_string );

		libcnotify_printf(
		 "%s: number of hits\t\t\t\t: %" PRIu32 "\n",
		 function,
		 url_values->number_of_hits );

		if( ( io_handle->major_version == 4 )
		 && ( io_handle->minor_version == 7 ) )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (msiecf_url_record_header_v47_t *) url_record_data )->unknown9,
			 value_32bit );
		}
		else if( ( io_handle->major_version == 5 )
		      && ( io_handle->minor_version == 2 ) )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (msiecf_url_record_header_v52_t *) url_record_data )->unknown9,
			 value_32bit );
		}
		libcnotify_printf(
		 "%s: unknown9\t\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		if( ( io_handle->major_version == 4 )
		 && ( io_handle->minor_version == 7 ) )
		{
			result = libfdatetime_fat_date_time_copy_from_byte_stream(
			          fat_date_time,
			          ( (msiecf_url_record_header_v47_t *) url_record_data )->unknown_time,
			          4,
			          LIBFDATETIME_ENDIAN_LITTLE,
			          error );
		}
		else if( ( io_handle->major_version == 5 )
		      && ( io_handle->minor_version == 2 ) )
		{
			result = libfdatetime_fat_date_time_copy_from_byte_stream(
			          fat_date_time,
			          ( (msiecf_url_record_header_v52_t *) url_record_data )->unknown_time,
			          4,
			          LIBFDATETIME_ENDIAN_LITTLE,
			          error );
		}
		if( result != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
			 LIBCERROR_CONVERSION_ERROR_GENERIC,
			 "%s: unable to copy FAT date time from byte stream.",
			 function );

			goto on_error;
		}
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
		result = libfdatetime_fat_date_time_copy_to_utf16_string(
		          fat_date_time,
		          (uint16_t *) date_time_string,
		          32,
		          LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
		          error );
#else
		result = libfdatetime_fat_date_time_copy_to_utf8_string(
		          fat_date_time,
		          (uint8_t *) date_time_string,
		          32,
		          LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
		          error );
#endif
		if( result != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_CONVERSION,
			 LIBCERROR_CONVERSION_ERROR_GENERIC,
			 "%s: unable to create FAT date time string.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "%s: unknown time\t\t\t\t\t: %" PRIs_SYSTEM "\n",
		 function,
		 date_time_string );

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

			goto on_error;
		}
		if( libfdatetime_fat_date_time_free(
		     &fat_date_time,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
			 "%s: unable to free FAT date time.",
			 function );

			goto on_error;
		}
	}
#endif
	if( unknown_offset > 0 )
	{
		if( unknown_offset > record_size )
		{
			if( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
				 "%s: unknown offset exceeds URL record data.",
				 function );

				goto on_error;
			}
			else
			{
				memory_free(
				 url_record_data );

				return( 1 );
			}
		}
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: unknown:\n",
			 function );
			libcnotify_print_data(
			 &( url_record_data[ unknown_offset ] ),
			 8,
			 0 );
		}
#endif
	}
	if( location_offset > 0 )
	{
		if( location_offset > record_size )
		{
			if( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
				 "%s: location offset exceeds size of URL record data.",
				 function );

				return( -1 );
			}
		}
		else
		{
			if( libfvalue_value_type_initialize(
			     &( url_values->location ),
			     LIBFVALUE_VALUE_TYPE_STRING_BYTE_STREAM,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
				 "%s: unable to create location value.",
				 function );

				goto on_error;
			}
			value_size = libfvalue_value_type_set_data_string(
			              url_values->location,
			              &( url_record_data[ location_offset ] ),
			              record_size - location_offset,
			              io_handle->ascii_codepage,
			              LIBFVALUE_VALUE_DATA_FLAG_MANAGED,
			              error );

			if( value_size == -1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
				 "%s: unable to set data of location value.",
				 function );

				goto on_error;
			}
#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: location\t\t\t\t\t: ",
				 function );

				if( libfvalue_value_print(
				     url_values->location,
				     0,
				     0,
				     error ) != 1 )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
					 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
					 "%s: unable to print location value.",
					 function );

					goto on_error;
				}
				libcnotify_printf(
				 "\n" );

				if( libmsiecf_hash_calculate(
				     &value_32bit,
				     &( url_record_data[ location_offset ] ),
				     record_size - location_offset,
				     error ) != 1 )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
					 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
					 "%s: unable to calculate location hash.",
					 function );

					goto on_error;
				}
				libcnotify_printf(
				 "%s: hash value\t\t\t\t\t: 0x%08" PRIx32 "\n",
				 function,
				 value_32bit );
			}
#endif
			if( ( url_record_data[ location_offset + value_size - 1 ] != 0 )
			 && ( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 ) )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
				 "%s: unsupported unterminated location string.",
				 function );

				goto on_error;
			}
			if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_UNDEFINED )
			{
				if( value_size >= 18 )
				{
					if( ( url_record_data[ location_offset ] == (uint8_t) ':' )
					 && ( url_record_data[ location_offset + 1 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 1 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 2 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 2 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 3 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 3 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 4 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 4 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 5 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 5 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 6 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 6 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 7 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 7 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 8 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 8 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 9 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 9 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 10 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 10 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 11 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 11 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 12 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 12 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 13 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 13 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 14 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 14 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 15 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 15 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 16 ] >= (uint8_t) '0' )
					 && ( url_record_data[ location_offset + 16 ] <= (uint8_t) '9' )
					 && ( url_record_data[ location_offset + 17 ] == (uint8_t) ':' ) )
					{
						first_year  = (uint16_t) url_record_data[ location_offset + 1 ] - (uint8_t) '0';
						first_year *= 10;
						first_year += (uint16_t) url_record_data[ location_offset + 2 ] - (uint8_t) '0';
						first_year *= 10;
						first_year += (uint16_t) url_record_data[ location_offset + 3 ] - (uint8_t) '0';
						first_year *= 10;
						first_year += (uint16_t) url_record_data[ location_offset + 4 ] - (uint8_t) '0';

						first_month  = url_record_data[ location_offset + 5 ] - (uint8_t) '0';
						first_month *= 10;
						first_month += url_record_data[ location_offset + 6 ] - (uint8_t) '0';

						first_day_of_month  = url_record_data[ location_offset + 7 ] - (uint8_t) '0';
						first_day_of_month *= 10;
						first_day_of_month += url_record_data[ location_offset + 8 ] - (uint8_t) '0';

						second_year  = (uint16_t) url_record_data[ location_offset + 9 ] - (uint8_t) '0';
						second_year *= 10;
						second_year += (uint16_t) url_record_data[ location_offset + 10 ] - (uint8_t) '0';
						second_year *= 10;
						second_year += (uint16_t) url_record_data[ location_offset + 11 ] - (uint8_t) '0';
						second_year *= 10;
						second_year += (uint16_t) url_record_data[ location_offset + 12 ] - (uint8_t) '0';

						second_month  = url_record_data[ location_offset + 13 ] - (uint8_t) '0';
						second_month *= 10;
						second_month += url_record_data[ location_offset + 14 ] - (uint8_t) '0';

						second_day_of_month  = url_record_data[ location_offset + 15 ] - (uint8_t) '0';
						second_day_of_month *= 10;
						second_day_of_month += url_record_data[ location_offset + 16 ] - (uint8_t) '0';

						number_of_days = 0;

						if( first_year == second_year )
						{
							if( first_month == second_month )
							{
								if( first_day_of_month < second_day_of_month )
								{
									number_of_days = second_day_of_month - first_day_of_month;
								}
							}
							else if( ( first_month + 1 ) == second_month )
							{
								switch( first_month )
								{
									case 3:
									case 5:
									case 7:
									case 8:
									case 10:
									case 12:
										number_of_days = ( 31 + second_day_of_month ) - first_day_of_month;
										break;

									case 2:
										if( ( ( ( first_year % 4 ) == 0 )
										  &&  ( ( first_year % 100 ) != 0 ) )
										 || ( ( first_year % 400 ) == 0 ) )
										{
											number_of_days = ( 29 + second_day_of_month ) - first_day_of_month;
										}
										else
										{
											number_of_days = ( 28 + second_day_of_month ) - first_day_of_month;
										}
										break;

									case 4:
									case 6:
									case 9:
									case 11:
										number_of_days = ( 30 + second_day_of_month ) - first_day_of_month;
										break;
								}
							}
						}
						else if( ( first_year + 1 ) == second_year )
						{
							if( ( first_month == 12 )
							 && ( second_month == 1 ) )
							{
								number_of_days = ( 31 + second_day_of_month ) - first_day_of_month;
							}
						}
						if( number_of_days == 1 )
						{
							url_values->type = LIBMSIECF_URL_ITEM_TYPE_HISTORY_DAILY;
						}
						else if( number_of_days == 7 )
						{
							url_values->type = LIBMSIECF_URL_ITEM_TYPE_HISTORY_WEEKLY;
						}
					}
				}
			}
			if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_UNDEFINED )
			{
				if( value_size >= 11 )
				{
					if( memory_compare(
					     &( url_record_data[ location_offset ] ),
					     "iedownload:",
					     11 ) == 0 )
					{
						url_values->type = LIBMSIECF_URL_ITEM_TYPE_DOWNLOAD;
					}
				}
			}
			if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_UNDEFINED )
			{
				if( value_size >= 9 )
				{
					if( memory_compare(
					     &( url_record_data[ location_offset ] ),
					     "DOMStore:",
					     9 ) == 0 )
					{
						url_values->type = LIBMSIECF_URL_ITEM_TYPE_DOM_STORE;
					}
					else if( memory_compare(
					          &( url_record_data[ location_offset ] ),
					          "feedplat:",
					          9 ) == 0 )
					{
						url_values->type = LIBMSIECF_URL_ITEM_TYPE_RSS_FEED;
					}
					else if( memory_compare(
					          &( url_record_data[ location_offset ] ),
					          "iecompat:",
					          9 ) == 0 )
					{
						url_values->type = LIBMSIECF_URL_ITEM_TYPE_COMPATIBILITY;
					}
					else if( memory_compare(
					          &( url_record_data[ location_offset ] ),
					          "PrivacIE:",
					          9 ) == 0 )
					{
						url_values->type = LIBMSIECF_URL_ITEM_TYPE_INPRIVATE_FILTERING;
					}
					else if( memory_compare(
					          &( url_record_data[ location_offset ] ),
					          "userdata:",
					          9 ) == 0 )
					{
						url_values->type = LIBMSIECF_URL_ITEM_TYPE_USER_DATA;
					}
				}
			}
			if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_UNDEFINED )
			{
				if( value_size >= 8 )
				{
					if( memory_compare(
					     &( url_record_data[ location_offset ] ),
					     "Visited:",
					     8 ) == 0 )
					{
						url_values->type = LIBMSIECF_URL_ITEM_TYPE_HISTORY;
					}
				}
			}
			if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_UNDEFINED )
			{
				if( value_size >= 7 )
				{
					if( memory_compare(
					     &( url_record_data[ location_offset ] ),
					     "Cookie:",
					     7 ) == 0 )
					{
						url_values->type = LIBMSIECF_URL_ITEM_TYPE_COOKIE;
					}
				}
			}
			if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_UNDEFINED )
			{
				if( value_size >= 6 )
				{
					if( memory_compare(
					     &( url_record_data[ location_offset ] ),
					     "ietld:",
					     6 ) == 0 )
					{
						url_values->type = LIBMSIECF_URL_ITEM_TYPE_TLD;
					}
				}
			}
			if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_UNDEFINED )
			{
				url_values->type = LIBMSIECF_URL_ITEM_TYPE_CACHE;

/* TODO way to determine unknown
				url_values->type = LIBMSIECF_URL_ITEM_TYPE_UNKNOWN;
*/
			}
		}
	}
	if( filename_offset > 0 )
	{
		if( filename_offset > record_size )
		{
			if( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
				 "%s: filename offset exceeds size of URL record data.",
				 function );

				goto on_error;
			}
		}
		else
		{
			if( libfvalue_value_type_initialize(
			     &( url_values->filename ),
			     LIBFVALUE_VALUE_TYPE_STRING_BYTE_STREAM,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
				 "%s: unable to create filename value.",
				 function );

				goto on_error;
			}
			value_size = libfvalue_value_type_set_data_string(
			              url_values->filename,
			              &( url_record_data[ filename_offset ] ),
			              record_size - filename_offset,
			              io_handle->ascii_codepage,
			              LIBFVALUE_VALUE_DATA_FLAG_MANAGED,
			              error );

			if( value_size == -1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
				 "%s: unable to set data of filename value.",
				 function );

				goto on_error;
			}
#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: filename\t\t\t\t\t: ",
				 function );

				if( libfvalue_value_print(
				     url_values->filename,
				     0,
				     0,
				     error ) != 1 )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
					 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
					 "%s: unable to print filename value.",
					 function );

					goto on_error;
				}
				libcnotify_printf(
				 "\n" );
			}
#endif
			if( ( url_record_data[ filename_offset + value_size - 1 ] != 0 )
			 && ( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 ) )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
				 "%s: unsupported unterminated filename string.",
				 function );

				goto on_error;
			}
		}
	}
	if( data_offset > 0 )
	{
		if( data_offset > record_size )
		{
			if( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
				 "%s: data offset exceeds size of URL record data.",
				 function );

				goto on_error;
			}
		}
		else
		{
			if( ( data_offset + data_size ) > record_size )
			{
				if( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
					 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
					 "%s: data size exceeds size of URL record data.",
					 function );

					goto on_error;
				}
				else
				{
					data_size = record_size - data_offset;
				}
			}
			url_values->data_size = (size_t) data_size;

			url_values->data = (uint8_t *) memory_allocate(
			                                sizeof( uint8_t ) * url_values->data_size );

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

				goto on_error;
			}
			if( memory_copy(
			     url_values->data,
			     &( url_record_data[ data_offset ] ),
			     url_values->data_size ) == NULL )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_MEMORY,
				 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
				 "%s: unable to copy data.",
				 function );

				goto on_error;
			}
#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: data:\n",
				 function );
				libcnotify_print_data(
				 &( url_record_data[ data_offset ] ),
				 data_size,
				 0 );

				if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_CACHE )
				{
					/* The data string in not necessarily terminated by an end-of-string character
					 */
					libcnotify_printf(
					 "%s: data string\t\t\t\t\t: ",
					 function );

					for( string_index = 0;
					     string_index < data_size;
					     string_index++ )
					{
						libcnotify_printf(
						 "%c",
						 url_record_data[ data_offset + string_index ] );
					}
					libcnotify_printf(
					 "\n" );
				}
				else if( url_values->type == LIBMSIECF_URL_ITEM_TYPE_HISTORY )
				{
					visited_entry_data = &( url_record_data[ data_offset ] );

					do
					{
						visited_entry_index++;

						byte_stream_copy_to_uint16_little_endian(
						 visited_entry_data,
						 value_16bit );

						visited_entry_data += 2;

						libcnotify_printf(
						 "%s: data entry: %02d size\t\t\t\t: %" PRIu16 "\n",
						 function,
						 visited_entry_index,
						 value_16bit );

						libcnotify_printf(
						 "%s: data entry: %02d type\t\t\t\t: 0x%02" PRIx8 " (%s : %s)\n",
						 function,
						 visited_entry_index,
						 visited_entry_data[ 0 ],
						 libmsiecf_property_type_get_identifier(
						  NULL,
						  (uint32_t) visited_entry_data[ 0 ],
						  (uint32_t) visited_entry_data[ 1 ] ),
						 libmsiecf_property_type_get_description(
						  NULL,
						  (uint32_t) visited_entry_data[ 0 ],
						  (uint32_t) visited_entry_data[ 1 ] ) );

						libcnotify_printf(
						 "%s: data entry: %02d value type\t\t\t: 0x%02" PRIx8 " (%s : %s)\n",
						 function,
						 visited_entry_index,
						 visited_entry_data[ 1 ],
						 libfole_value_type_get_identifier(
						  (uint32_t) visited_entry_data[ 1 ] ),
						 libfole_value_type_get_description(
						  (uint32_t) visited_entry_data[ 1 ] ) );

						visited_entry_data += 2;

						if( value_16bit > 4 )
						{
							value_16bit -= 4;

							libcnotify_printf(
							 "%s: data entry: %02d value:\n",
							 function,
							 visited_entry_index );
							libcnotify_print_data(
							 visited_entry_data,
							 value_16bit,
							 0 );

							visited_entry_data += value_16bit;
						}
					}
					while( value_16bit > 0 );
				}
			}
#endif
		}
	}
	memory_free(
	 url_record_data );

	url_record_data = NULL;

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "\n" );
	}
#endif
#if defined( HAVE_VERBOSE_OUTPUT )
	switch( url_values->type )
	{
		case LIBMSIECF_URL_ITEM_TYPE_COOKIE:
			if ( ( cache_entry_flags & LIBMSIECF_CACHE_ENTRY_FLAG_COOKIE ) == 0 )
			{
				libcnotify_printf(
				 "%s: detected type cookie but corresponding cache entry flag (COOKIE_CACHE_ENTRY) is not set.\n",
				 function );
			}
			break;

		case LIBMSIECF_URL_ITEM_TYPE_HISTORY:
			if ( ( cache_entry_flags & LIBMSIECF_CACHE_ENTRY_FLAG_URLHISTORY ) == 0 )
			{
				libcnotify_printf(
				 "%s: detected type history but corresponding cache entry flag (URLHISTORY_CACHE_ENTRY) is not set.\n",
				 function );
			}
			break;

		case LIBMSIECF_URL_ITEM_TYPE_HISTORY_DAILY:
		case LIBMSIECF_URL_ITEM_TYPE_HISTORY_WEEKLY:
			if ( ( cache_entry_flags & LIBMSIECF_CACHE_ENTRY_FLAG_URLHISTORY ) == 0 )
			{
				libcnotify_printf(
				 "%s: detected type history periodic but corresponding cache entry flag (URLHISTORY_CACHE_ENTRY) is not set.\n",
				 function );
			}
			break;
	}
#endif
	return( 1 );

on_error:
#if defined( HAVE_DEBUG_OUTPUT )
	if( filetime != NULL )
	{
		libfdatetime_filetime_free(
		 &filetime,
		 NULL );
	}
	if( fat_date_time != NULL )
	{
		libfdatetime_fat_date_time_free(
		 &fat_date_time,
		 NULL );
	}
#endif
	if( url_record_data != NULL )
	{
		memory_free(
		 url_record_data );
	}
	return( -1 );
}
Exemple #2
0
/* Reads the memory image information
 * Returns 1 if successful or -1 on error
 */
int libhibr_io_handle_read_memory_image_information(
     libhibr_io_handle_t *io_handle,
     libbfio_handle_t *file_io_handle,
     libcerror_error_t **error )
{
	uint8_t *page_data                          = NULL;
	static char *function                       = "libhibr_io_handle_read_memory_image_information";
	ssize_t read_count                          = 0;
	uint64_t page_size                          = 0;
	uint32_t memory_image_information_data_size = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	libcstring_system_character_t filetime_string[ 32 ];

	libfdatetime_filetime_t *filetime           = NULL;
	uint64_t value_64bit                        = 0;
	uint32_t value_32bit                        = 0;
	uint8_t value_8bit                          = 0;
	int result                                  = 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 defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: reading memory image information at offset: 0.\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 memory image information offset: 0.",
		 function );

		goto on_error;
	}
	page_data = (uint8_t *) memory_allocate(
	                         sizeof( uint8_t ) * io_handle->page_size );

	if( page_data == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
		 "%s: unable to create memory image information data.",
		 function );

		goto on_error;
	}
	read_count = libbfio_handle_read_buffer(
	              file_io_handle,
	              page_data,
	              io_handle->page_size,
	              error );

	if( read_count != (ssize_t) io_handle->page_size )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_READ_FAILED,
		 "%s: unable to read memory image information.",
		 function );

		goto on_error;
	}
/* TODO do empty page test */

	byte_stream_copy_to_uint32_little_endian(
	 ( (hibr_memory_image_information_t *) page_data )->size,
	 memory_image_information_data_size );

	if( memory_image_information_data_size > 0 )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: memory image information data:\n",
			 function );
			libcnotify_print_data(
			 page_data,
			 (size_t) memory_image_information_data_size,
			 0 );
		}
#endif
/* TODO
		if( memory_compare(
		     ( (hibr_memory_image_information_t *) page_data )->signature,
		     hibr_file_signature,
		     8 ) != 0 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
			 "%s: unsupported file signature.",
			 function );

			goto on_error;
		}
*/
		if( memory_image_information_data_size == sizeof( hibr_memory_image_information_winxp_32bit_t ) )
		{
			io_handle->file_type = LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT;
		}
		else if( memory_image_information_data_size == sizeof( hibr_memory_image_information_winxp_64bit_t ) )
		{
			io_handle->file_type = LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT;
		}
		else if( memory_image_information_data_size == sizeof( hibr_memory_image_information_win7_32bit_t ) )
		{
			io_handle->file_type = LIBHIBR_FILE_TYPE_WINDOWS_7_32BIT;
		}
		else if( memory_image_information_data_size == sizeof( hibr_memory_image_information_win7_64bit_t ) )
		{
			io_handle->file_type = LIBHIBR_FILE_TYPE_WINDOWS_7_64BIT;
		}
		if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->page_size,
			 page_size );
		}
		else if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (hibr_memory_image_information_winxp_64bit_t *) page_data )->page_size,
			 page_size );
		}
		else if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_7_32BIT )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (hibr_memory_image_information_win7_32bit_t *) page_data )->page_size,
			 page_size );
		}
		else if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_7_64BIT )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (hibr_memory_image_information_win7_64bit_t *) page_data )->page_size,
			 page_size );
		}
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: signature\t\t: %c%c%c%c\n",
			 function,
			 ( (hibr_memory_image_information_t *) page_data )->signature[ 0 ],
			 ( (hibr_memory_image_information_t *) page_data )->signature[ 1 ],
			 ( (hibr_memory_image_information_t *) page_data )->signature[ 2 ],
			 ( (hibr_memory_image_information_t *) page_data )->signature[ 3 ] );

			if( ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			 || ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT ) )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->version,
				 value_32bit );
				libcnotify_printf(
				 "%s: version\t\t: %" PRIu32 "\n",
				 function,
				 value_32bit );
			}
			else if( ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_7_32BIT )
			      || ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_7_64BIT ) )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_win7_32bit_t *) page_data )->image_type,
				 value_32bit );
				libcnotify_printf(
				 "%s: image type\t\t: %" PRIu32 "\n",
				 function,
				 value_32bit );
			}
			byte_stream_copy_to_uint32_little_endian(
			 ( (hibr_memory_image_information_t *) page_data )->checksum,
			 value_32bit );
			libcnotify_printf(
			 "%s: checksum\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			libcnotify_printf(
			 "%s: size\t\t\t: %" PRIu32 "\n",
			 function,
			 memory_image_information_data_size );

			if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->page_number,
				 value_64bit );
			}
			else if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT )
			{
				byte_stream_copy_to_uint64_little_endian(
				 ( (hibr_memory_image_information_winxp_64bit_t *) page_data )->page_number,
				 value_64bit );
			}
			else if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_7_32BIT )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_win7_32bit_t *) page_data )->page_number,
				 value_64bit );
			}
			else if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_7_64BIT )
			{
				byte_stream_copy_to_uint64_little_endian(
				 ( (hibr_memory_image_information_win7_64bit_t *) page_data )->page_number,
				 value_64bit );
			}
			libcnotify_printf(
			 "%s: page number\t\t: %" PRIu64 "\n",
			 function,
			 value_64bit );

			libcnotify_printf(
			 "%s: page size\t\t: %" PRIu64 "\n",
			 function,
			 page_size );

			if( ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			 || ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT ) )
			{
				if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
				{
					byte_stream_copy_to_uint32_little_endian(
					 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->image_type,
					 value_32bit );
				}
				else
				{
					byte_stream_copy_to_uint32_little_endian(
					 ( (hibr_memory_image_information_winxp_64bit_t *) page_data )->image_type,
					 value_32bit );
				}
				libcnotify_printf(
				 "%s: image type\t\t: %" PRIu32 "\n",
				 function,
				 value_32bit );
			}
			if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->unknown1,
				 value_32bit );
				libcnotify_printf(
				 "%s: unknown1\t\t: 0x%08" PRIx32 "\n",
				 function,
				 value_32bit );
			}
			if( ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			 || ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT ) )
			{
				byte_stream_copy_to_uint64_little_endian(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->system_time,
				 value_64bit );
			}
			else if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_7_32BIT )
			{
				byte_stream_copy_to_uint64_little_endian(
				 ( (hibr_memory_image_information_win7_32bit_t *) page_data )->system_time,
				 value_64bit );
			}
			else if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_7_64BIT )
			{
				byte_stream_copy_to_uint64_little_endian(
				 ( (hibr_memory_image_information_win7_64bit_t *) page_data )->system_time,
				 value_64bit );
			}
			if( libfdatetime_filetime_initialize(
			     &filetime,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
				 "%s: unable to create filetime.",
				 function );

				goto on_error;
			}
			if( libfdatetime_filetime_copy_from_64bit(
			     filetime,
			     value_64bit,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
				 "%s: unable to copy byte stream to filetime.",
				 function );

				goto on_error;
			}
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
			result = libfdatetime_filetime_copy_to_utf16_string(
				  filetime,
				  (uint16_t *) filetime_string,
				  32,
				  LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
				  error );
#else
			result = libfdatetime_filetime_copy_to_utf8_string(
				  filetime,
				  (uint8_t *) filetime_string,
				  32,
				  LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
				  error );
#endif
			if( result != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
				 "%s: unable to copy filetime to string.",
				 function );

				goto on_error;
			}
			libcnotify_printf(
			 "%s: system time\t\t: %" PRIs_LIBCSTRING_SYSTEM " UTC\n",
			 function,
			 filetime_string );

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

				goto on_error;
			}
			if( ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			 || ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT ) )
			{
				byte_stream_copy_to_uint64_little_endian(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->interrupt_time,
				 value_64bit );
			}
			libcnotify_printf(
			 "%s: interrupt time\t\t: 0x%08" PRIx64 "\n",
			 function,
			 value_64bit );

			if( ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			 || ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT ) )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->feature_flags,
				 value_32bit );
			}
			libcnotify_printf(
			 "%s: feature flags\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			if( ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			 || ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT ) )
			{
				value_8bit = ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->hibernation_flags;
			}
			libcnotify_printf(
			 "%s: hibernation flags\t: 0x%02" PRIx8 "\n",
			 function,
			 value_8bit );

			if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			{
				libcnotify_printf(
				 "%s: unknown2:\n",
				 function );
				libcnotify_print_data(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->unknown2,
				 3,
				 0 );
			}
			else if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT )
			{
				libcnotify_printf(
				 "%s: unknown1:\n",
				 function );
				libcnotify_print_data(
				 ( (hibr_memory_image_information_winxp_64bit_t *) page_data )->unknown1,
				 3,
				 0 );

				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_64bit_t *) page_data )->unknown2,
				 value_32bit );
				libcnotify_printf(
				 "%s: unknown2\t\t: 0x%08" PRIx32 "\n",
				 function,
				 value_32bit );
			}
			if( ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			 || ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT ) )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->unknown3,
				 value_32bit );
			}
			libcnotify_printf(
			 "%s: unknown3\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			if( ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			 || ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT ) )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->unknown4,
				 value_32bit );
			}
			libcnotify_printf(
			 "%s: unknown4\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			if( ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			 || ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT ) )
			{
				byte_stream_copy_to_uint64_little_endian(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->unknown5,
				 value_64bit );
			}
			libcnotify_printf(
			 "%s: unknown5\t\t: 0x%08" PRIx64 "\n",
			 function,
			 value_64bit );

			if( ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			 || ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT ) )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->number_of_free_pages,
				 value_32bit );
			}
			libcnotify_printf(
			 "%s: number of free pages\t: %" PRIu32 "\n",
			 function,
			 value_32bit );

			if( ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			 || ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT ) )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->unknown6,
				 value_32bit );
			}
			libcnotify_printf(
			 "%s: unknown6\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			if( ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			 || ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT ) )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->unknown7,
				 value_32bit );
			}
			libcnotify_printf(
			 "%s: unknown7\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_64bit_t *) page_data )->unknown8,
				 value_32bit );
				libcnotify_printf(
				 "%s: unknown8\t\t: 0x%08" PRIx32 "\n",
				 function,
				 value_32bit );
			}
			if( ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			 || ( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT ) )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->number_of_pages,
				 value_32bit );
			}
			libcnotify_printf(
			 "%s: number of pages\t: %" PRIu32 "\n",
			 function,
			 value_32bit );

			if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_32BIT )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->unknown8,
				 value_32bit );
				libcnotify_printf(
				 "%s: unknown8\t\t: 0x%08" PRIx32 "\n",
				 function,
				 value_32bit );

				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->unknown9,
				 value_32bit );
				libcnotify_printf(
				 "%s: unknown9\t\t: 0x%08" PRIx32 "\n",
				 function,
				 value_32bit );

				libcnotify_printf(
				 "%s: unknown10:\n",
				 function );
				libcnotify_print_data(
				 ( (hibr_memory_image_information_winxp_32bit_t *) page_data )->unknown10,
				 72,
				 0 );
			}
			else if( io_handle->file_type == LIBHIBR_FILE_TYPE_WINDOWS_XP_64BIT )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_64bit_t *) page_data )->unknown8,
				 value_32bit );
				libcnotify_printf(
				 "%s: unknown8\t\t: 0x%08" PRIx32 "\n",
				 function,
				 value_32bit );

				byte_stream_copy_to_uint32_little_endian(
				 ( (hibr_memory_image_information_winxp_64bit_t *) page_data )->unknown9,
				 value_32bit );
				libcnotify_printf(
				 "%s: unknown9\t\t: 0x%08" PRIx32 "\n",
				 function,
				 value_32bit );

				libcnotify_printf(
				 "%s: unknown10:\n",
				 function );
				libcnotify_print_data(
				 ( (hibr_memory_image_information_winxp_64bit_t *) page_data )->unknown10,
				 72,
				 0 );
			}
			else
			{
				libcnotify_printf(
				 "\n" );
			}
		}
#endif
	}
#if defined( HAVE_DEBUG_OUTPUT )
	else if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: page data:\n",
		 function );
		libcnotify_print_data(
		 page_data,
		 io_handle->page_size,
		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
	}
#endif
/* TODO print trailing data */

/* TODO page size sanity check */
	io_handle->page_size = (size_t) page_size;

/* TODO memory blocks page number sanity check */

	memory_free(
	 page_data );

	page_data = NULL;

	return( 1 );

on_error:
#if defined( HAVE_DEBUG_OUTPUT )
	if( filetime != NULL )
	{
		libfdatetime_filetime_free(
		 &filetime,
		 NULL );
	}
#endif
	if( page_data != NULL )
	{
		memory_free(
		 page_data );
	}
	return( -1 );
}
Exemple #3
0
/* Reads the volume header
 * Returns 1 if successful or -1 on error
 */
int libbde_io_handle_read_volume_header(
     libbde_io_handle_t *io_handle,
     libbfio_handle_t *file_io_handle,
     off64_t file_offset,
     libcerror_error_t **error )
{
	uint8_t *volume_header_data      = NULL;
	static char *function            = "libbde_io_handle_read_volume_header";
	size_t read_size                 = 512;
	ssize_t read_count               = 0;
	uint64_t total_number_of_sectors = 0;

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

	libfguid_identifier_t *guid      = NULL;
	uint64_t value_64bit             = 0;
	uint32_t value_32bit             = 0;
	uint16_t value_16bit             = 0;
	int result                       = 0;
#endif

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

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: reading volume header at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
		 function,
		 file_offset,
		 file_offset );
	}
#endif
	if( libbfio_handle_seek_offset(
	     file_io_handle,
	     file_offset,
	     SEEK_SET,
	     error ) == -1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_SEEK_FAILED,
		 "%s: unable to seek volume header offset: %" PRIi64 ".",
		 function,
		 file_offset );

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

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

		goto on_error;
	}
	read_count = libbfio_handle_read_buffer(
	              file_io_handle,
	              volume_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 volume header data.",
		 function );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: volume header data:\n",
		 function );
		libcnotify_print_data(
		 volume_header_data,
		 read_size,
		 0 );
	}
#endif
	if( memory_compare(
	     volume_header_data,
	     bde_boot_entry_point_vista,
	     3 ) == 0 )
	{
		io_handle->version = LIBBDE_VERSION_WINDOWS_VISTA;
	}
	else if( memory_compare(
	          volume_header_data,
	          bde_boot_entry_point_win7,
	          3 ) == 0 )
	{
		if( memory_compare(
		     ( (bde_volume_header_windows_7_t *) volume_header_data )->identifier,
		     bde_identifier,
		     16 ) == 0 )
		{
			io_handle->version = LIBBDE_VERSION_WINDOWS_7;
		}
		else if( memory_compare(
		          ( (bde_volume_header_to_go_t *) volume_header_data )->identifier,
		          bde_identifier,
		          16 ) == 0 )
		{
			io_handle->version = LIBBDE_VERSION_TO_GO;
		}
		else
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
			 "%s: unsupported identifier.",
			 function );

			goto on_error;
		}
	}
	else
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported volume boot entry point.",
		 function );

		goto on_error;
	}
	if( ( io_handle->version == LIBBDE_VERSION_WINDOWS_VISTA )
	 || ( io_handle->version == LIBBDE_VERSION_WINDOWS_7 ) )
	{
		if( memory_compare(
		     &( volume_header_data[ 3 ] ),
		     bde_signature,
		     8 ) != 0 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
			 "%s: invalid volume signature.",
			 function );

			goto on_error;
		}
	}
	byte_stream_copy_to_uint16_little_endian(
	 ( (bde_volume_header_windows_vista_t *) volume_header_data )->bytes_per_sector,
	 io_handle->bytes_per_sector );

	io_handle->sectors_per_cluster_block = ( (bde_volume_header_windows_vista_t *) volume_header_data )->sectors_per_cluster_block;

	byte_stream_copy_to_uint16_little_endian(
	 ( (bde_volume_header_windows_vista_t *) volume_header_data )->total_number_of_sectors_16bit,
	 total_number_of_sectors );

	if( total_number_of_sectors == 0 )
	{
		byte_stream_copy_to_uint32_little_endian(
		 ( (bde_volume_header_windows_vista_t *) volume_header_data )->total_number_of_sectors_32bit,
		 total_number_of_sectors );
	}
	if( io_handle->version == LIBBDE_VERSION_WINDOWS_VISTA )
	{
		byte_stream_copy_to_uint64_little_endian(
		 ( (bde_volume_header_windows_vista_t *) volume_header_data )->first_metadata_cluster_block_number,
		 io_handle->first_metadata_offset );

		if( total_number_of_sectors == 0 )
		{
			byte_stream_copy_to_uint64_little_endian(
			 ( (bde_volume_header_windows_vista_t *) volume_header_data )->total_number_of_sectors_64bit,
			 total_number_of_sectors );
		}
	}
	else if( io_handle->version == LIBBDE_VERSION_WINDOWS_7 )
	{
		byte_stream_copy_to_uint64_little_endian(
		 ( (bde_volume_header_windows_7_t *) volume_header_data )->first_metadata_offset,
		 io_handle->first_metadata_offset );

		byte_stream_copy_to_uint64_little_endian(
		 ( (bde_volume_header_windows_7_t *) volume_header_data )->second_metadata_offset,
		 io_handle->second_metadata_offset );

		byte_stream_copy_to_uint64_little_endian(
		 ( (bde_volume_header_windows_7_t *) volume_header_data )->third_metadata_offset,
		 io_handle->third_metadata_offset );
	}
	else if( io_handle->version == LIBBDE_VERSION_TO_GO )
	{
		byte_stream_copy_to_uint64_little_endian(
		 ( (bde_volume_header_to_go_t *) volume_header_data )->first_metadata_offset,
		 io_handle->first_metadata_offset );

		byte_stream_copy_to_uint64_little_endian(
		 ( (bde_volume_header_to_go_t *) volume_header_data )->second_metadata_offset,
		 io_handle->second_metadata_offset );

		byte_stream_copy_to_uint64_little_endian(
		 ( (bde_volume_header_to_go_t *) volume_header_data )->third_metadata_offset,
		 io_handle->third_metadata_offset );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: boot entry point:\n",
		 function );
		libcnotify_print_data(
		 volume_header_data,
		 3,
		 0 );

		libcnotify_printf(
		 "%s: signature\t\t\t\t: %c%c%c%c%c%c%c%c\n",
		 function,
		 volume_header_data[ 3 ],
		 volume_header_data[ 4 ],
		 volume_header_data[ 5 ],
		 volume_header_data[ 6 ],
		 volume_header_data[ 7 ],
		 volume_header_data[ 8 ],
		 volume_header_data[ 9 ],
		 volume_header_data[ 10 ] );

		libcnotify_printf(
		 "%s: bytes per sector\t\t\t: %" PRIu16 "\n",
		 function,
		 io_handle->bytes_per_sector );

		libcnotify_printf(
		 "%s: sectors per cluster block\t\t: %" PRIu8 "\n",
		 function,
		 io_handle->sectors_per_cluster_block );

		libcnotify_printf(
		 "%s: unknown1\n",
		 function );
		libcnotify_print_data(
		 ( (bde_volume_header_windows_vista_t *) volume_header_data )->unknown1,
		 5,
		 0 );

		byte_stream_copy_to_uint16_little_endian(
		 ( (bde_volume_header_windows_vista_t *) volume_header_data )->total_number_of_sectors_16bit,
		 value_16bit );
		libcnotify_printf(
		 "%s: total number of sectors (16-bit)\t: %" PRIu16 "\n",
		 function,
		 value_16bit );

		libcnotify_printf(
		 "%s: media descriptor\t\t\t: 0x%02" PRIx8 "\n",
		 function,
		 ( (bde_volume_header_windows_vista_t *) volume_header_data )->media_descriptor );

		byte_stream_copy_to_uint16_little_endian(
		 ( (bde_volume_header_windows_vista_t *) volume_header_data )->unknown2,
		 value_16bit );
		libcnotify_printf(
		 "%s: unknown2\t\t\t\t: %" PRIu16 "\n",
		 function,
		 value_16bit );

		byte_stream_copy_to_uint16_little_endian(
		 ( (bde_volume_header_windows_vista_t *) volume_header_data )->sectors_per_track,
		 value_16bit );
		libcnotify_printf(
		 "%s: sectors per track\t\t\t: %" PRIu16 "\n",
		 function,
		 value_16bit );

		byte_stream_copy_to_uint16_little_endian(
		 ( (bde_volume_header_windows_vista_t *) volume_header_data )->number_of_heads,
		 value_16bit );
		libcnotify_printf(
		 "%s: number of heads\t\t\t: %" PRIu16 "\n",
		 function,
		 value_16bit );

		byte_stream_copy_to_uint32_little_endian(
		 ( (bde_volume_header_windows_vista_t *) volume_header_data )->number_of_hidden_sectors,
		 value_32bit );
		libcnotify_printf(
		 "%s: number of hidden sectors\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 ( (bde_volume_header_windows_vista_t *) volume_header_data )->total_number_of_sectors_32bit,
		 value_32bit );
		libcnotify_printf(
		 "%s: total number of sectors (32-bit)\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		if( io_handle->version == LIBBDE_VERSION_WINDOWS_VISTA )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (bde_volume_header_windows_vista_t *) volume_header_data )->unknown4,
			 value_32bit );
			libcnotify_printf(
			 "%s: unknown4\t\t\t\t: 0x%08" PRIx32 " (%" PRIu32 ")\n",
			 function,
			 value_32bit,
			 value_32bit );

			byte_stream_copy_to_uint32_little_endian(
			 ( (bde_volume_header_windows_vista_t *) volume_header_data )->total_number_of_sectors_64bit,
			 value_64bit );
			libcnotify_printf(
			 "%s: total number of sectors (64-bit)\t: %" PRIu64 "\n",
			 function,
			 value_64bit );

			byte_stream_copy_to_uint64_little_endian(
			 ( (bde_volume_header_windows_vista_t *) volume_header_data )->mft_cluster_block_number,
			 value_64bit );
			libcnotify_printf(
			 "%s: MFT cluster block number\t\t: %" PRIu64 "\n",
			 function,
			 value_64bit );

			libcnotify_printf(
			 "%s: first metadata cluster block\t: 0x%08" PRIx64 "\n",
			 function,
			 io_handle->first_metadata_offset );

			byte_stream_copy_to_uint32_little_endian(
			 ( (bde_volume_header_windows_vista_t *) volume_header_data )->mft_entry_size,
			 value_32bit );
			libcnotify_printf(
			 "%s: MFT entry size\t\t\t: %" PRIu32 "\n",
			 function,
			 value_32bit );

			byte_stream_copy_to_uint32_little_endian(
			 ( (bde_volume_header_windows_vista_t *) volume_header_data )->index_entry_size,
			 value_32bit );
			libcnotify_printf(
			 "%s: index entry size\t\t: %" PRIu32 "\n",
			 function,
			 value_32bit );

			byte_stream_copy_to_uint64_little_endian(
			 ( (bde_volume_header_windows_vista_t *) volume_header_data )->volume_serial_number,
			 value_64bit );
			libcnotify_printf(
			 "%s: volume serial number\t\t: 0x%08" PRIx64 "\n",
			 function,
			 value_64bit );

			byte_stream_copy_to_uint32_little_endian(
			 ( (bde_volume_header_windows_vista_t *) volume_header_data )->checksum,
			 value_32bit );
			libcnotify_printf(
			 "%s: checksum\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			libcnotify_printf(
			 "%s: bootcode\n",
			 function );
			libcnotify_print_data(
			 ( (bde_volume_header_windows_vista_t *) volume_header_data )->bootcode,
			 426,
			 0 );
		}
		else if( ( io_handle->version == LIBBDE_VERSION_WINDOWS_7 )
		      || ( io_handle->version == LIBBDE_VERSION_TO_GO ) )
		{
			libcnotify_printf(
			 "%s: unknown4:\n",
			 function );
			libcnotify_print_data(
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->unknown4,
			 31,
			 0 );

			byte_stream_copy_to_uint32_little_endian(
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->volume_serial_number,
			 value_64bit );
			libcnotify_printf(
			 "%s: volume serial number\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			libcnotify_printf(
			 "%s: volume label\t\t\t: %c%c%c%c%c%c%c%c%c%c%c\n",
			 function,
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->volume_label[ 0 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->volume_label[ 1 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->volume_label[ 2 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->volume_label[ 3 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->volume_label[ 4 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->volume_label[ 5 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->volume_label[ 6 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->volume_label[ 7 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->volume_label[ 8 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->volume_label[ 9 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->volume_label[ 10 ] );

			libcnotify_printf(
			 "%s: file system signature\t\t: %c%c%c%c%c%c%c%c\n",
			 function,
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->file_system_signature[ 0 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->file_system_signature[ 1 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->file_system_signature[ 2 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->file_system_signature[ 3 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->file_system_signature[ 4 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->file_system_signature[ 5 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->file_system_signature[ 6 ],
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->file_system_signature[ 7 ] );
		}
		if( io_handle->version == LIBBDE_VERSION_WINDOWS_7 )
		{
			libcnotify_printf(
			 "%s: bootcode\n",
			 function );
			libcnotify_print_data(
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->bootcode,
			 47,
			 0 );

			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,
			     ( (bde_volume_header_windows_7_t *) volume_header_data )->identifier,
			     16,
			     LIBFGUID_ENDIAN_LITTLE,
			     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: identifier\t\t\t\t: %" PRIs_LIBCSTRING_SYSTEM "\n",
			 function,
			 guid_string );

			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;
			}
		}
		else if( io_handle->version == LIBBDE_VERSION_TO_GO )
		{
			libcnotify_printf(
			 "%s: bootcode\n",
			 function );
			libcnotify_print_data(
			 ( (bde_volume_header_to_go_t *) volume_header_data )->bootcode,
			 335,
			 0 );

			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,
			     ( (bde_volume_header_to_go_t *) volume_header_data )->identifier,
			     16,
			     LIBFGUID_ENDIAN_LITTLE,
			     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: identifier\t\t\t\t: %" PRIs_LIBCSTRING_SYSTEM "\n",
			 function,
			 guid_string );

			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;
			}
		}
		if( ( io_handle->version == LIBBDE_VERSION_WINDOWS_7 )
		 || ( io_handle->version == LIBBDE_VERSION_TO_GO ) )
		{
			libcnotify_printf(
			 "%s: first metadata offset\t\t: 0x%08" PRIx64 "\n",
			 function,
			 io_handle->first_metadata_offset );

			libcnotify_printf(
			 "%s: second metadata offset\t\t: 0x%08" PRIx64 "\n",
			 function,
			 io_handle->second_metadata_offset );

			libcnotify_printf(
			 "%s: third metadata offset\t\t: 0x%08" PRIx64 "\n",
			 function,
			 io_handle->third_metadata_offset );
		}
		if( io_handle->version == LIBBDE_VERSION_WINDOWS_7 )
		{
			libcnotify_printf(
			 "%s: unknown5:\n",
			 function );
			libcnotify_print_data(
			 ( (bde_volume_header_windows_7_t *) volume_header_data )->unknown5,
			 310,
			 0 );
		}
		else if( io_handle->version == LIBBDE_VERSION_TO_GO )
		{
			libcnotify_printf(
			 "%s: unknown5:\n",
			 function );
			libcnotify_print_data(
			 ( (bde_volume_header_to_go_t *) volume_header_data )->unknown5,
			 46,
			 0 );
		}
		byte_stream_copy_to_uint16_little_endian(
		 ( (bde_volume_header_windows_vista_t *) volume_header_data )->sector_signature,
		 value_16bit );
		libcnotify_printf(
		 "%s: sector signature\t\t\t: 0x%04" PRIx16 "\n",
		 function,
		 value_16bit );

		libcnotify_printf(
		 "\n" );
	}
#endif
	if( total_number_of_sectors != 0 )
	{
		io_handle->volume_size  = total_number_of_sectors;
		io_handle->volume_size *= io_handle->bytes_per_sector;
	}
	if( io_handle->version == LIBBDE_VERSION_WINDOWS_VISTA )
	{
		io_handle->first_metadata_offset *= io_handle->sectors_per_cluster_block;
		io_handle->first_metadata_offset *= io_handle->bytes_per_sector;

		io_handle->metadata_size = 16384;
	}
	else if( ( io_handle->version == LIBBDE_VERSION_WINDOWS_7 )
	      || ( io_handle->version == LIBBDE_VERSION_TO_GO ) )
	{
		io_handle->metadata_size = 65536;
	}
	memory_free(
	 volume_header_data );

	volume_header_data = NULL;

	return( 1 );

on_error:
#if defined( HAVE_DEBUG_OUTPUT )
	if( guid != NULL )
	{
		libfguid_identifier_free(
		 &guid,
		 NULL );
	}
#endif
	if( volume_header_data != NULL )
	{
		memory_free(
		 volume_header_data );
	}
	return( -1 );
}
Exemple #4
0
/* Copies the record from the byte stream
 * Returns 1 if successful or -1 on error
 */
int libfusn_record_copy_from_byte_stream(
     libfusn_record_t *record,
     const uint8_t *byte_stream,
     size_t byte_stream_size,
     libcerror_error_t **error )
{
	libfusn_internal_record_t *internal_record = NULL;
	static char *function                      = "libfusn_record_copy_from_byte_stream";
	size_t byte_stream_offset                  = 0;
	uint16_t name_offset                       = 0;
	uint16_t name_size                         = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	uint32_t value_32bit                       = 0;
#endif

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

		return( -1 );
	}
	internal_record = (libfusn_internal_record_t *) record;

	if( internal_record->name != NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
		 "%s: invalid record - name value already set.",
		 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 );
	}
	if( byte_stream_size < sizeof( fusn_record_header_t ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
		 "%s: invalid byte stream value too small.",
		 function );

		return( -1 );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: record header data:\n",
		 function );
		libcnotify_print_data(
		 byte_stream,
		 sizeof( fusn_record_header_t ),
		 0 );
	}
#endif
	byte_stream_copy_to_uint32_little_endian(
	 ( (fusn_record_header_t *) byte_stream )->record_size,
	 internal_record->size );

	byte_stream_copy_to_uint16_little_endian(
	 ( (fusn_record_header_t *) byte_stream )->major_version,
	 internal_record->major_version );

	byte_stream_copy_to_uint16_little_endian(
	 ( (fusn_record_header_t *) byte_stream )->minor_version,
	 internal_record->minor_version );

	byte_stream_copy_to_uint64_little_endian(
	 ( (fusn_record_header_t *) byte_stream )->update_time,
	 internal_record->update_time );

	byte_stream_copy_to_uint64_little_endian(
	 ( (fusn_record_header_t *) byte_stream )->file_reference,
	 internal_record->file_reference );

	byte_stream_copy_to_uint32_little_endian(
	 ( (fusn_record_header_t *) byte_stream )->file_attribute_flags,
	 internal_record->file_attribute_flags );

	byte_stream_copy_to_uint64_little_endian(
	 ( (fusn_record_header_t *) byte_stream )->parent_file_reference,
	 internal_record->parent_file_reference );

	byte_stream_copy_to_uint64_little_endian(
	 ( (fusn_record_header_t *) byte_stream )->update_sequence_number,
	 internal_record->update_sequence_number );

	byte_stream_copy_to_uint32_little_endian(
	 ( (fusn_record_header_t *) byte_stream )->update_reason_flags,
	 internal_record->update_reason_flags );

	byte_stream_copy_to_uint32_little_endian(
	 ( (fusn_record_header_t *) byte_stream )->update_source_flags,
	 internal_record->update_source_flags );

	byte_stream_copy_to_uint16_little_endian(
	 ( (fusn_record_header_t *) byte_stream )->name_size,
	 name_size );

	byte_stream_copy_to_uint16_little_endian(
	 ( (fusn_record_header_t *) byte_stream )->name_offset,
	 name_offset );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: record size\t\t\t: %" PRIu32 "\n",
		 function,
		 internal_record->size );

		libcnotify_printf(
		 "%s: major version\t\t\t: %" PRIu16 "\n",
		 function,
		 internal_record->major_version );

		libcnotify_printf(
		 "%s: minor version\t\t\t: %" PRIu16 "\n",
		 function,
		 internal_record->minor_version );

		libcnotify_printf(
		 "%s: file reference\t\t\t: MFT entry: %" PRIu64 ", sequence: %" PRIu64 "\n",
		 function,
		 internal_record->file_reference & 0xffffffffffffUL,
		 internal_record->file_reference >> 48 );

		libcnotify_printf(
		 "%s: parent file reference\t\t: MFT entry: %" PRIu64 ", sequence: %" PRIu64 "\n",
		 function,
		 internal_record->parent_file_reference & 0xffffffffffffUL,
		 internal_record->parent_file_reference >> 48 );

		libcnotify_printf(
		 "%s: update sequence number\t\t: 0x%08" PRIx64 "\n",
		 function,
		 internal_record->update_sequence_number );

		if( libfusn_debug_print_filetime_value(
		     function,
		     "update time\t\t\t",
		     ( (fusn_record_header_t *) byte_stream )->update_time,
		     8,
		     LIBFDATETIME_ENDIAN_LITTLE,
		     LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
			 "%s: unable to print FILETIME value.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "%s: update reason flags\t\t: 0x%08" PRIx32 "\n",
		 function,
		 internal_record->update_reason_flags );
		libfusn_debug_print_update_reason_flags(
		 internal_record->update_reason_flags );
		libcnotify_printf(
		 "\n" );

		libcnotify_printf(
		 "%s: update source flags\t\t: 0x%08" PRIx32 "\n",
		 function,
		 internal_record->update_source_flags );
		libfusn_debug_print_update_source_flags(
		 internal_record->update_source_flags );
		libcnotify_printf(
		 "\n" );

		byte_stream_copy_to_uint32_little_endian(
		 ( (fusn_record_header_t *) byte_stream )->security_identifier_index,
		 value_32bit );
		libcnotify_printf(
		 "%s: security identifier index\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		libcnotify_printf(
		 "%s: file attribute flags\t\t: 0x%08" PRIx32 "\n",
		 function,
		 internal_record->file_attribute_flags );
		libfusn_debug_print_file_attribute_flags(
		 internal_record->file_attribute_flags );
		libcnotify_printf(
		 "\n" );

		libcnotify_printf(
		 "%s: name size\t\t\t\t: %" PRIu16 "\n",
		 function,
		 name_size );

		libcnotify_printf(
		 "%s: name offset\t\t\t: %" PRIu16 "\n",
		 function,
		 name_offset );
	}
Exemple #5
0
/* Retrieves a specific string identifier
 * Returns 1 if successful or -1 on error
 */
int libwrc_string_get_identifier(
     libwrc_resource_t *resource,
     uint32_t language_identifier,
     int string_index,
     uint32_t *string_identifier,
     libcerror_error_t **error )
{
	libfvalue_value_t *string_values    = NULL;
	uint8_t *string_value_identifier    = NULL;
	static char *function               = "libwrc_string_get_identifier";
	size_t string_value_identifier_size = 0;

	if( libwrc_resource_get_value_by_language_identifier(
	     resource,
	     LIBWRC_RESOURCE_TYPE_STRING,
	     language_identifier,
	     string_index,
	     (intptr_t **) &string_values,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve string values.",
		 function );

		return( -1 );
	}
/* TODO move to string values function */
	if( string_identifier == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid string identifier.",
		 function );

		return( -1 );
	}
	if( libfvalue_value_get_identifier(
	     string_values,
	     &string_value_identifier,
	     &string_value_identifier_size,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve string value: %d identifier.",
		 function,
		 string_index );

		return( -1 );
	}
	if( string_value_identifier == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: missing string value identifier.",
		 function );

		return( -1 );
	}
	if( string_value_identifier_size != 4 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
		 "%s: string value dentifier size value out of bound.",
		 function );

		return( -1 );
	}
	byte_stream_copy_to_uint32_little_endian(
	 string_value_identifier,
	 *string_identifier );

	return( 1 );
}
/* Reads the reparse point values
 * Returns 1 if successful or -1 on error
 */
int libfsntfs_reparse_point_values_read(
     libfsntfs_reparse_point_values_t *reparse_point_values,
     const uint8_t *data,
     size_t data_size,
     libcerror_error_t **error )
{
	static char *function = "libfsntfs_reparse_point_values_read";

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

	if( reparse_point_values == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid reparse point values.",
		 function );

		return( -1 );
	}
	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 > (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 defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: reparse point data:\n",
		 function );
		libcnotify_print_data(
		 data,
		 data_size,
		 0 );
	}
#endif
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		byte_stream_copy_to_uint32_little_endian(
		 ( (fsntfs_reparse_point_t *) data )->type,
		 value_32bit );
		libcnotify_printf(
		 "%s: type and flags\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint16_little_endian(
		 ( (fsntfs_reparse_point_t *) data )->data_size,
		 value_16bit );
		libcnotify_printf(
		 "%s: data size\t\t\t\t\t: 0x%04" PRIx16 "\n",
		 function,
		 value_16bit );

		libcnotify_printf(
		 "\n" );
	}
#endif
	return( 1 );
}
/* Reads a redirected
 * Returns 1 if successful or -1 on error
 */
int libmsiecf_redirected_values_read(
     libmsiecf_redirected_values_t *redirected_values,
     libmsiecf_io_handle_t *io_handle,
     libbfio_handle_t *file_io_handle,
     off64_t redirected_offset,
     size32_t record_size,
     uint8_t item_flags,
     libcerror_error_t **error )
{
	uint8_t *redr_record_data = NULL;
	static char *function     = "libmsiecf_redirected_values_read";
	ssize_t read_count        = 0;
	ssize_t value_size        = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	uint32_t value_32bit      = 0;
#endif

	if( redirected_values == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid redirected values.",
		 function );

		return( -1 );
	}
	if( record_size == 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_ZERO_OR_LESS,
		 "%s: invalid record size value zero or less.",
		 function );

		return( -1 );
	}
#if SIZEOF_SIZE_T <= 4
	if( record_size > (size32_t) SSIZE_MAX )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
		 "%s: invalid record size value exceeds maximum.",
		 function );

		return( -1 );
	}
#endif
	if( ( record_size % 8 ) != 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported REDR record size.",
		 function );

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

		goto on_error;
	}
	redr_record_data = (uint8_t *) memory_allocate(
	                                sizeof( uint8_t ) * record_size );

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

		goto on_error;
	}
	read_count = libbfio_handle_read_buffer(
	              file_io_handle,
	              redr_record_data,
	              record_size,
	              error );

	if( read_count != (ssize_t) record_size )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_READ_FAILED,
		 "%s: unable to read REDR record data.",
		 function );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: REDR record data:\n",
		 function );
		libcnotify_print_data(
		 redr_record_data,
		 record_size,
		 0 );
	}
#endif
	if( memory_compare(
	     ( (msiecf_redr_record_header_t *) redr_record_data )->signature,
	     "REDR",
	     4 ) != 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported signature.",
		 function );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: signature\t\t\t\t: %c%c%c%c\n",
		 function,
		 ( (msiecf_redr_record_header_t *) redr_record_data )->signature[ 0 ],
		 ( (msiecf_redr_record_header_t *) redr_record_data )->signature[ 1 ],
		 ( (msiecf_redr_record_header_t *) redr_record_data )->signature[ 2 ],
		 ( (msiecf_redr_record_header_t *) redr_record_data )->signature[ 3 ] );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_redr_record_header_t *) redr_record_data )->number_of_blocks,
		 value_32bit );
		libcnotify_printf(
		 "%s: number of blocks\t\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_redr_record_header_t *) redr_record_data )->unknown1,
		 value_32bit );
		libcnotify_printf(
		 "%s: unknown1\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 ( (msiecf_redr_record_header_t *) redr_record_data )->unknown2,
		 value_32bit );
		libcnotify_printf(
		 "%s: unknown2\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );
	}
#endif
	if( libfvalue_value_type_initialize(
	     &( redirected_values->location ),
	     LIBFVALUE_VALUE_TYPE_STRING_BYTE_STREAM,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
		 "%s: unable to create location value.",
		 function );

		goto on_error;
	}
	value_size = libfvalue_value_type_set_data_string(
	              redirected_values->location,
	              &( redr_record_data[ 16 ] ),
	              record_size - 16,
	              io_handle->ascii_codepage,
	              LIBFVALUE_VALUE_DATA_FLAG_MANAGED,
	              error );

	if( value_size == -1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
		 "%s: unable to set data of location value.",
		 function );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: location\t\t\t\t: ",
		 function );

		if( libfvalue_value_print(
		     redirected_values->location,
		     0,
		     0,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
			 "%s: unable to print location value.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "\n" );

		if( libmsiecf_hash_calculate(
		     &value_32bit,
		     &( redr_record_data[ 16 ] ),
		     record_size - 16,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
			 "%s: unable to calculate location hash.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "%s: hash value\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );
	}
#endif
	if( ( redr_record_data[ 16 + value_size - 1 ] != 0 )
	 && ( ( item_flags & LIBMSIECF_ITEM_FLAG_PARTIAL ) == 0 ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported unterminated location string.",
		 function );

		goto on_error;
	}
	memory_free(
	 redr_record_data );

	redr_record_data = NULL;

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "\n" );
	}
#endif
	return( 1 );

on_error:
	if( redirected_values->location != NULL )
	{
		libfvalue_value_free(
		 &( redirected_values->location ),
		 NULL );
	}
	if( redr_record_data != NULL )
	{
		memory_free(
		 redr_record_data );
	}
	return( -1 );
}
/* Reads distributed link tracker properties
 * Returns the number of bytes read if successful or -1 on error
 */
int liblnk_distributed_link_tracker_properties_read(
     liblnk_distributed_link_tracker_properties_t *distributed_link_tracker_properties,
     liblnk_data_block_t *data_block,
     liblnk_io_handle_t *io_handle,
     libcerror_error_t **error )
{
	lnk_data_block_distributed_link_tracker_properties_t *distributed_link_tracker_properties_data = NULL;
	static char *function                                                                          = "liblnk_distributed_link_tracker_properties_read";
	uint32_t data_size                                                                             = 0;
	uint32_t data_version                                                                          = 0;

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

	libcstring_system_character_t *value_string                                                    = NULL;
	libfguid_identifier_t *guid                                                                    = NULL;
	size_t value_string_size                                                                       = 0;
	int result                                                                                     = 0;
#endif

	if( distributed_link_tracker_properties == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid distributed link tracker properties.",
		 function );

		return( -1 );
	}
	if( data_block == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%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( data_block->data_size < sizeof( lnk_data_block_distributed_link_tracker_properties_t ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
		 "%s: invalid data block - data size too small.",
		 function );

		return( -1 );
	}
	distributed_link_tracker_properties_data = (lnk_data_block_distributed_link_tracker_properties_t *) data_block->data;

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

		return( -1 );
	}
	byte_stream_copy_to_uint32_little_endian(
	 distributed_link_tracker_properties_data->data_size,
	 data_size );

	byte_stream_copy_to_uint32_little_endian(
	 distributed_link_tracker_properties_data->data_version,
	 data_version );

	if( data_version != 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported data version: %" PRIu32 ".",
		 function,
		 data_version );

		goto on_error;
	}
/* TODO check if data size matches data block size */
	if( data_size < 88 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported data size: %" PRIu32 ".",
		 function,
		 data_size );

		goto on_error;
	}
	if( memory_copy(
	     distributed_link_tracker_properties->machine_identifier_string,
	     distributed_link_tracker_properties_data->machine_identifier_string,
	     16 ) == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
		 "%s: unable to copy machine identifier string.",
		 function );

		goto on_error;
	}
	if( memory_copy(
	     distributed_link_tracker_properties->droid_volume_identifier,
	     distributed_link_tracker_properties_data->droid_volume_identifier,
	     16 ) == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
		 "%s: unable to copy droid volume identifier.",
		 function );

		goto on_error;
	}
	if( memory_copy(
	     distributed_link_tracker_properties->droid_file_identifier,
	     distributed_link_tracker_properties_data->droid_file_identifier,
	     16 ) == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
		 "%s: unable to copy droid file identifier.",
		 function );

		goto on_error;
	}
	if( memory_copy(
	     distributed_link_tracker_properties->birth_droid_volume_identifier,
	     distributed_link_tracker_properties_data->birth_droid_volume_identifier,
	     16 ) == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
		 "%s: unable to copy birth droid volume identifier.",
		 function );

		goto on_error;
	}
	if( memory_copy(
	     distributed_link_tracker_properties->birth_droid_file_identifier,
	     distributed_link_tracker_properties_data->birth_droid_file_identifier,
	     16 ) == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
		 "%s: unable to copy birth droid file identifier.",
		 function );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: data size\t\t\t: %" PRIu32 "\n",
		 function,
		 data_size );

		libcnotify_printf(
		 "%s: data version\t\t\t: %" PRIu32 "\n",
		 function,
		 data_version );

		libcnotify_printf(
		 "%s: machine identifier string data:\n",
		 function );
		libcnotify_print_data(
		 distributed_link_tracker_properties_data->machine_identifier_string,
		 16,
		 0 );

#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
		result = libuna_utf16_string_size_from_byte_stream(
			  distributed_link_tracker_properties_data->machine_identifier_string,
			  16,
			  io_handle->ascii_codepage,
			  &value_string_size,
			  error );
#else
		result = libuna_utf8_string_size_from_byte_stream(
			  distributed_link_tracker_properties_data->machine_identifier_string,
			  16,
			  io_handle->ascii_codepage,
			  &value_string_size,
			  error );
#endif
		if( result != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
			 "%s: unable to determine size of machine identifier string.",
			 function );

			goto on_error;
		}
		if( ( value_string_size > (size_t) SSIZE_MAX )
		 || ( ( sizeof( libcstring_system_character_t ) * value_string_size )  > (size_t) SSIZE_MAX ) )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
			 "%s: invalid machine identifier string size value exceeds maximum.",
			 function );

			goto on_error;
		}
		value_string = libcstring_system_string_allocate(
				value_string_size );

		if( value_string == NULL )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_MEMORY,
			 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
			 "%s: unable to create machine identifier string.",
			 function );

			goto on_error;
		}
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
		result = libuna_utf16_string_copy_from_byte_stream(
			  (libuna_utf16_character_t *) value_string,
			  value_string_size,
			  distributed_link_tracker_properties_data->machine_identifier_string,
			  16,
			  io_handle->ascii_codepage,
			  error );
#else
		result = libuna_utf8_string_copy_from_byte_stream(
			  (libuna_utf8_character_t *) value_string,
			  value_string_size,
			  distributed_link_tracker_properties_data->machine_identifier_string,
			  16,
			  io_handle->ascii_codepage,
			  error );
#endif
		if( result != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
			 "%s: unable to set machine identifier string.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "%s: machine identifier string\t: %" PRIs_LIBCSTRING_SYSTEM "\n",
		 function,
		 value_string );

		memory_free(
		 value_string );

		value_string = NULL;

		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,
		     distributed_link_tracker_properties->droid_volume_identifier,
		     16,
		     LIBFGUID_ENDIAN_LITTLE,
		     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: droid volume identifier\t: %" PRIs_LIBCSTRING_SYSTEM "\n",
		 function,
		 guid_string );

		if( libfguid_identifier_copy_from_byte_stream(
		     guid,
		     distributed_link_tracker_properties->droid_file_identifier,
		     16,
		     LIBFGUID_ENDIAN_LITTLE,
		     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: droid file identifier\t\t: %" PRIs_LIBCSTRING_SYSTEM "\n",
		 function,
		 guid_string );

		if( libfguid_identifier_copy_from_byte_stream(
		     guid,
		     distributed_link_tracker_properties->birth_droid_volume_identifier,
		     16,
		     LIBFGUID_ENDIAN_LITTLE,
		     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: birth droid volume identifier\t: %" PRIs_LIBCSTRING_SYSTEM "\n",
		 function,
		 guid_string );

		if( libfguid_identifier_copy_from_byte_stream(
		     guid,
		     distributed_link_tracker_properties->birth_droid_file_identifier,
		     16,
		     LIBFGUID_ENDIAN_LITTLE,
		     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: birth droid file identifier\t: %" PRIs_LIBCSTRING_SYSTEM "\n",
		 function,
		 guid_string );

		libcnotify_printf(
		 "\n" );

		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;
		}
	}
#endif
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		if( data_block->data_size > sizeof( lnk_data_block_distributed_link_tracker_properties_t ) )
		{
			libcnotify_printf(
			 "%s: trailing data:\n",
			 function );
			libcnotify_print_data(
			 &( data_block->data[ sizeof( lnk_data_block_distributed_link_tracker_properties_t ) ] ),
			 data_block->data_size - sizeof( lnk_data_block_distributed_link_tracker_properties_t ),
			 0 );
		}
	}
#endif
	return( 1 );

on_error:
#if defined( HAVE_DEBUG_OUTPUT )
	if( guid != NULL )
	{
		libfguid_identifier_free(
		 &guid,
		 NULL );
	}
	if( value_string != NULL )
	{
		memory_free(
		 value_string );
	}
#endif
	return( -1 );
}
/* Reads the space tree page
 * Returns 1 if successful or -1 on error
 */
int libesedb_page_tree_read_space_tree_page(
     libesedb_page_tree_t *page_tree,
     libbfio_handle_t *file_io_handle,
     uint32_t page_number,
     libcerror_error_t **error )
{
	libesedb_page_t *page             = NULL;
	libesedb_page_value_t *page_value = NULL;
	uint8_t *page_value_data          = NULL;
	static char *function             = "libesedb_page_tree_read_space_tree_page";
	uint32_t number_of_pages          = 0;
	uint32_t required_flags           = 0;
	uint32_t supported_flags          = 0;
	uint32_t total_number_of_pages    = 0;
	uint16_t number_of_page_values    = 0;
	uint16_t key_size                 = 0;
	uint16_t page_value_index         = 0;
	uint16_t page_value_size          = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	uint8_t *page_key_data            = NULL;
	size_t page_key_size              = 0;
#endif

	if( page_tree == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid page tree.",
		 function );

		return( -1 );
	}
	if( libfdata_vector_get_element_value_by_index(
	     page_tree->pages_vector,
	     (intptr_t *) file_io_handle,
	     page_tree->pages_cache,
	     (int) page_number - 1,
	     (intptr_t **) &page,
	     0,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve page: %" PRIu32 ".",
		 function,
		 page_number );

		return( -1 );
	}
	if( page == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: missing page.",
		 function );

		return( -1 );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		if( page_tree->object_identifier != page->father_data_page_object_identifier )
		{
			libcnotify_printf(
			 "%s: mismatch in father data page object identifier (tree: %" PRIu32 " != page: %" PRIu32 ").",
			 function,
			 page_tree->object_identifier,
			 page->father_data_page_object_identifier );
		}
	}
#endif
	required_flags = LIBESEDB_PAGE_FLAG_IS_ROOT
	               | LIBESEDB_PAGE_FLAG_IS_SPACE_TREE;

	if( ( page->flags & required_flags ) != required_flags )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: missing required page flags: 0x%08" PRIx32 ".",
		 function,
		 page->flags );

		return( -1 );
	}
	if( ( page->flags & LIBESEDB_PAGE_FLAG_IS_EMPTY ) != 0 )
	{
		return( 1 );
	}
	supported_flags = required_flags
	                | LIBESEDB_PAGE_FLAG_IS_LEAF
	                | LIBESEDB_PAGE_FLAG_IS_PARENT
	                | LIBESEDB_PAGE_FLAG_IS_INDEX
	                | LIBESEDB_PAGE_FLAG_IS_LONG_VALUE
	                | LIBESEDB_PAGE_FLAG_0x0400
	                | LIBESEDB_PAGE_FLAG_0x0800
	                | LIBESEDB_PAGE_FLAG_IS_NEW_RECORD_FORMAT
	                | LIBESEDB_PAGE_FLAG_IS_SCRUBBED
	                | LIBESEDB_PAGE_FLAG_0x8000;

	if( ( page->flags & ~supported_flags ) != 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported page flags: 0x%08" PRIx32 ".",
		 function,
		 page->flags );

		return( -1 );
	}
	if( page->previous_page_number != 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported previous page number: %" PRIu32 ".",
		 function,
		 page->previous_page_number );

		return( -1 );
	}
	if( page->next_page_number != 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported next page number: %" PRIu32 ".",
		 function,
		 page->next_page_number );

		return( -1 );
	}
	if( libesedb_page_get_number_of_values(
	     page,
	     &number_of_page_values,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve number of page values.",
		 function );

		return( -1 );
	}
	if( number_of_page_values == 0 )
	{
		return( 1 );
	}
	if( libesedb_page_get_value(
	     page,
	     page_value_index,
	     &page_value,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve page value: %" PRIu16 ".",
		 function,
		 page_value_index );

		return( -1 );
	}
	if( page_value == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: invalid page value.",
		 function );

		return( -1 );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: page value: %03" PRIu16 " data:\n",
		 function,
		 page_value_index );
		libcnotify_print_data(
		 page_value->data,
		 (size_t) page_value->size,
		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );

		libcnotify_printf(
		 "%s: page value: %03" PRIu16 " page tag flags\t\t: 0x%02" PRIx8 "",
		 function,
		 page_value_index,
		 page_value->flags );
		libesedb_debug_print_page_tag_flags(
		 page_value->flags );

		libcnotify_printf(
		 "\n" );
	}
#endif
	page_value_data = page_value->data;
	page_value_size = page_value->size;

	if( ( page->flags & LIBESEDB_PAGE_FLAG_IS_LEAF ) != 0 )
	{
		if( page_value_size != 16 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
			 "%s: unsupported header size.",
			 function );

			return( -1 );
		}
	}
/* TODO handle the space tree page header */
	for( page_value_index = 1;
	     page_value_index < number_of_page_values;
	     page_value_index++ )
	{
		if( libesedb_page_get_value(
		     page,
		     page_value_index,
		     &page_value,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
			 "%s: unable to retrieve page value: %" PRIu16 ".",
			 function,
			 page_value_index );

			return( -1 );
		}
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: page value: %03" PRIu16 " data:\n",
			 function,
			 page_value_index );
			libcnotify_print_data(
			 page_value->data,
			 (size_t) page_value->size,
			 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );

			libcnotify_printf(
			 "%s: page value: %03" PRIu16 " page tag flags\t\t: 0x%02" PRIx8 "",
			 function,
			 page_value_index,
			 page_value->flags );
			libesedb_debug_print_page_tag_flags(
			 page_value->flags );

			libcnotify_printf(
			 "\n" );
		}
#endif
		page_value_data = page_value->data;
		page_value_size = page_value->size;

		if( ( page->flags & LIBESEDB_PAGE_FLAG_IS_LEAF ) != 0 )
		{
			if( ( page_value->flags & 0x05 ) != 0 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
				 "%s: unsupported page value flags: 0x%02" PRIx8 ".",
				 function,
				 page_value->flags );

				return( -1 );
			}
			if( page_value_size < 2 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
				 "%s: unsupported key size value out of bounds.",
				 function );

				return( -1 );
			}
			byte_stream_copy_to_uint16_little_endian(
			 page_value_data,
			 key_size );

			page_value_data += 2;
			page_value_size -= 2;

#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: page value: %03" PRIu16 " key size\t\t: %" PRIu16 "\n",
				 function,
				 page_value_index,
				 key_size );
			}
#endif
			if( key_size > page_value_size )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
				 "%s: unsupported key size value out of bounds.",
				 function );

				return( -1 );
			}
#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: page value: %03" PRIu16 " key value\t\t: ",
				 function,
				 page_value_index );

				page_key_data = page_value_data;
				page_key_size = key_size;

				while( page_key_size > 0 )
				{
					libcnotify_printf(
					 "%02" PRIx8 " ",
					 *page_key_data );

					page_key_data++;
					page_key_size--;
				}
				libcnotify_printf(
				 "\n" );
			}
#endif
			page_value_data += key_size;
			page_value_size -= key_size;

			if( page_value_size < 4 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
				 "%s: unsupported key size value out of bounds.",
				 function );

				return( -1 );
			}
			byte_stream_copy_to_uint32_little_endian(
			 page_value_data,
			 number_of_pages );

			page_value_data += 4;
			page_value_size -= 4;

#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: page value: %03" PRIu16 " number of pages\t: %" PRIu32 "\n",
				 function,
				 page_value_index,
				 number_of_pages );

				libcnotify_printf(
				 "\n" );
			}
#endif
			if( ( page_value->flags & LIBESEDB_PAGE_TAG_FLAG_IS_DEFUNCT ) == 0 )
			{
				total_number_of_pages += number_of_pages;
			}
		}
		else if( ( page->flags & LIBESEDB_PAGE_FLAG_IS_PARENT ) != 0 )
		{
#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: data:\n",
				 function );
				libcnotify_print_data(
				 page_value_data,
				 (size_t) page_value_size,
				 0 );
			}
#endif
#ifdef TODO
/* TODO handle parent space tree pages */
			if( libesedb_page_tree_read_space_tree_page(
			     page_tree,
			     file_io_handle,
			     space_tree_page_number,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_IO,
				 LIBCERROR_IO_ERROR_READ_FAILED,
				 "%s: unable to read space tree page: %" PRIu32 ".",
				 function,
				 space_tree_page_number );

				return( -1 );
			}
#endif
		}
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: total number of pages\t\t\t: %" PRIu32 "\n",
		 function,
		 total_number_of_pages );

		libcnotify_printf(
		 "\n" );
	}
#endif
	return( 1 );
}
/* Reads a page
 * Returns 1 if successful or -1 on error
 */
int libesedb_page_tree_read_page(
     libesedb_page_tree_t *page_tree,
     libbfio_handle_t *file_io_handle,
     off64_t page_offset,
     uint32_t page_number,
     libfdata_btree_node_t *node,
     libcerror_error_t **error )
{
	libesedb_key_t *key                      = NULL;
	libesedb_page_value_t *header_page_value = NULL;
	libesedb_page_t *page                    = NULL;
	libesedb_page_value_t *page_value        = NULL;
	uint8_t *page_value_data                 = NULL;
	static char *function                    = "libesedb_page_tree_read_page";
	off64_t element_data_offset              = 0;
	off64_t sub_node_data_offset             = 0;
	uint32_t child_page_number               = 0;
	uint32_t supported_flags                 = 0;
	uint16_t common_key_size                 = 0;
	uint16_t local_key_size                  = 0;
	uint16_t number_of_page_values           = 0;
	uint16_t page_value_index                = 0;
	uint16_t page_value_offset               = 0;
	uint16_t page_value_size                 = 0;
	int element_index                        = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	uint8_t *page_key_data                   = NULL;
	size_t page_key_size                     = 0;
#endif

	if( page_tree == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid page tree.",
		 function );

		return( -1 );
	}
	if( page_tree->io_handle == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: invalid page tree - missing IO handle.",
		 function );

		return( -1 );
	}
	if( libfdata_vector_get_element_value_at_offset(
	     page_tree->pages_vector,
	     (intptr_t *) file_io_handle,
	     page_tree->pages_cache,
	     page_offset,
	     &element_data_offset,
	     (intptr_t **) &page,
	     0,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve page: %" PRIu32 " at offset: 0x%08" PRIx64 ".",
		 function,
		 page_number,
		 page_offset );

		goto on_error;
	}
	if( page == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: missing page.",
		 function );

		goto on_error;
	}
	if( ( page->flags & LIBESEDB_PAGE_FLAG_IS_EMPTY ) != 0 )
	{
		return( 1 );
	}
	supported_flags = LIBESEDB_PAGE_FLAG_IS_ROOT
	                | LIBESEDB_PAGE_FLAG_IS_LEAF
	                | LIBESEDB_PAGE_FLAG_IS_PARENT
	                | LIBESEDB_PAGE_FLAG_IS_INDEX
	                | LIBESEDB_PAGE_FLAG_IS_LONG_VALUE
	                | LIBESEDB_PAGE_FLAG_0x0400
	                | LIBESEDB_PAGE_FLAG_0x0800
	                | LIBESEDB_PAGE_FLAG_IS_NEW_RECORD_FORMAT
	                | LIBESEDB_PAGE_FLAG_IS_SCRUBBED
	                | LIBESEDB_PAGE_FLAG_0x8000;

	if( ( page->flags & ~supported_flags ) != 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported page flags: 0x%08" PRIx32 ".",
		 function,
		 page->flags );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( ( page->flags & LIBESEDB_PAGE_FLAG_IS_ROOT ) != 0 )
	{
/* TODO uncache the root page?
 */
		if( libesedb_page_tree_read_root_page(
		     page_tree,
		     file_io_handle,
		     page_offset,
		     page_number,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read root page: %" PRIu32 ".",
			 function,
			 page_number );

			goto on_error;
		}
		/* Since the previous function reads the space tree
		 * page can be cached out and we must be sure to re-read it.
		 */
		if( libfdata_vector_get_element_value_at_offset(
		     page_tree->pages_vector,
		     (intptr_t *) file_io_handle,
		     page_tree->pages_cache,
		     page_offset,
		     &element_data_offset,
		     (intptr_t **) &page,
		     0,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
			 "%s: unable to retrieve page: %" PRIu32 " at offset: 0x%08" PRIx64 ".",
			 function,
			 page_number,
			 page_offset );

			goto on_error;
		}
		if( page == NULL )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
			 "%s: missing page.",
			 function );

			goto on_error;
		}
	}
#endif
	if( ( page->flags & LIBESEDB_PAGE_FLAG_IS_LEAF ) != 0 )
	{
#ifdef TODO
/* TODO refactor */
			if( libcnotify_verbose != 0 )
			{
				if( page_value_index > 1 )
				{
					if( child_page->page_number != previous_next_child_page_number )
					{
						libcnotify_printf(
						 "%s: mismatch in child page number (%" PRIu32 " != %" PRIu32 ").\n",
						 function,
						 previous_next_child_page_number,
						 child_page->page_number );
					}
					if( child_page->previous_page_number != previous_child_page_number )
					{
						libcnotify_printf(
						 "%s: mismatch in previous child page number (%" PRIu32 " != %" PRIu32 ").\n",
						 function,
						 previous_child_page_number,
						 child_page->previous_page_number );
					}
				}
/* TODO need the actual values for the following checks
				if( page_value_index == 1 )
				{
					if( child_page->previous_page_number != 0 )
					{
						libcnotify_printf(
						 "%s: mismatch in previous child page number (%" PRIu32 " != %" PRIu32 ").",
						 function,
						 0,
						 child_page->previous_page_number );
					}
				}
				if( page_value_index == ( number_of_page_values - 1 ) )
				{
					if( child_page->next_page_number != 0 )
					{
						libcnotify_printf(
						 "%s: mismatch in next child page number (%" PRIu32 " != %" PRIu32 ").",
						 function,
						 0,
						 child_page->previous_page_number );
					}
				}
*/
			}
			previous_child_page_number      = child_page->page_number;
			previous_next_child_page_number = child_page->next_page_number;
#endif
	}
	else
	{
		if( page->previous_page_number != 0 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
			 "%s: unsupported previous page number: %" PRIu32 ".",
			 function,
			 page->previous_page_number );

			goto on_error;
		}
		if( page->next_page_number != 0 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
			 "%s: unsupported next page number: %" PRIu32 ".",
			 function,
			 page->next_page_number );

			goto on_error;
		}
	}
	if( libesedb_page_get_number_of_values(
	     page,
	     &number_of_page_values,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve number of page values.",
		 function );

		goto on_error;
	}
	if( number_of_page_values == 0 )
	{
		return( 1 );
	}
	for( page_value_index = 1;
	     page_value_index < number_of_page_values;
	     page_value_index++ )
	{
		if( libesedb_page_get_value(
		     page,
		     page_value_index,
		     &page_value,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
			 "%s: unable to retrieve page value: %" PRIu16 ".",
			 function,
			 page_value_index );

			goto on_error;
		}
		if( page_value == NULL )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
			 "%s: missing page value: %" PRIu16 ".",
			 function,
			 page_value_index );

			goto on_error;
		}
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: page value: %03" PRIu16 " data:\n",
			 function,
			 page_value_index );
			libcnotify_print_data(
			 page_value->data,
			 (size_t) page_value->size,
			 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );

			libcnotify_printf(
			 "%s: page value: %03" PRIu16 " page tag flags\t\t: 0x%02" PRIx8 "",
			 function,
			 page_value_index,
			 page_value->flags );
			libesedb_debug_print_page_tag_flags(
			 page_value->flags );

			libcnotify_printf(
			 "\n" );
		}
#endif
		if( ( page_value->flags & LIBESEDB_PAGE_TAG_FLAG_IS_DEFUNCT ) != 0 )
		{
			continue;
		}
/* TODO are defunct data definition of any value recovering
 */
		page_value_data   = page_value->data;
		page_value_offset = page_value->offset;
		page_value_size   = page_value->size;

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

			goto on_error;
		}
		if( key == NULL )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
			 "%s: missing key.",
			 function );

			goto on_error;
		}
		if( ( page_value->flags & LIBESEDB_PAGE_TAG_FLAG_HAS_COMMON_KEY_SIZE ) != 0 )
		{
			if( ( page->flags & LIBESEDB_PAGE_FLAG_IS_ROOT ) != 0 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
				 "%s: unsupported page flags - root flag is set.",
				 function );

				goto on_error;
			}
			if( libesedb_page_get_value(
			     page,
			     0,
			     &header_page_value,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
				 "%s: unable to retrieve page value: 0.",
				 function );

				goto on_error;
			}
			if( header_page_value == NULL )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
				 "%s: missing page value: 0.",
				 function );

				goto on_error;
			}
			byte_stream_copy_to_uint16_little_endian(
			 page_value_data,
			 common_key_size );

			page_value_data   += 2;
			page_value_offset += 2;
			page_value_size   -= 2;

#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: page value: %03" PRIu16 " common key size\t\t: %" PRIu16 "\n",
				 function,
				 page_value_index,
				 common_key_size );
			}
#endif
			if( common_key_size > header_page_value->size )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
				 "%s: common key size exceeds header page value size.",
				 function );

				goto on_error;
			}
#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: page value: %03" PRIu16 " common key value\t\t: ",
				 function,
				 page_value_index );

				page_key_data = header_page_value->data;
				page_key_size = common_key_size;

				while( page_key_size > 0 )
				{
					if( libcnotify_verbose != 0 )
					{
						libcnotify_printf(
						 "%02" PRIx8 " ",
						 *page_key_data );
					}
					page_key_data++;
					page_key_size--;
				}
				libcnotify_printf(
				 "\n" );
			}
#endif
			if( libesedb_key_set_data(
			     key,
			     header_page_value->data,
			     common_key_size,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
				 "%s: unable to set common key data in key.",
				 function );

				goto on_error;
			}
		}
		byte_stream_copy_to_uint16_little_endian(
		 page_value_data,
		 local_key_size );

		page_value_data   += 2;
		page_value_offset += 2;
		page_value_size   -= 2;

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: page value: %03" PRIu16 " local key size\t\t: %" PRIu16 "\n",
			 function,
			 page_value_index,
			 local_key_size );
		}
#endif
		if( local_key_size > page_value_size )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: local key size exceeds page value size.",
			 function );

			goto on_error;
		}
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: page value: %03" PRIu16 " local key value\t\t: ",
			 function,
			 page_value_index );

			page_key_data = page_value_data;
			page_key_size = local_key_size;

			while( page_key_size > 0 )
			{
				if( libcnotify_verbose != 0 )
				{
					libcnotify_printf(
					 "%02" PRIx8 " ",
					 *page_key_data );
				}
				page_key_data++;
				page_key_size--;
			}
			libcnotify_printf(
			 "\n" );
		}
#endif
		if( libesedb_key_append_data(
		     key,
		     page_value_data,
		     local_key_size,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
			 "%s: unable to append local key data to key.",
			 function );

			goto on_error;
		}
		page_value_data   += local_key_size;
		page_value_offset += local_key_size;
		page_value_size   -= local_key_size;

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: page value: %03" PRIu16 " key value\t\t\t: ",
			 function,
			 page_value_index );

			page_key_data = key->data;
			page_key_size = key->data_size;

			while( page_key_size > 0 )
			{
				libcnotify_printf(
				 "%02" PRIx8 " ",
				 *page_key_data );

				page_key_data++;
				page_key_size--;
			}
			libcnotify_printf(
			 "\n" );
		}
#endif
		if( ( page->flags & LIBESEDB_PAGE_FLAG_IS_LEAF ) != 0 )
		{
#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "\n" );
			}
#endif
			key->type = LIBESEDB_KEY_TYPE_LEAF;

			if( libfdata_btree_node_append_leaf_value(
			     node,
			     &element_index,
			     (int) page_value_index,
			     page_offset + page_value_offset,
			     (size64_t) page_value_size,
			     0,
			     (intptr_t *) key,
			     (int (*)(intptr_t **, libcerror_error_t **)) &libesedb_key_free,
			     LIBFDATA_KEY_VALUE_FLAG_MANAGED,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
				 "%s: unable to append page: %" PRIu32 " value: %" PRIu16 " as leaf value.",
				 function,
				 page_number,
				 page_value_index );

				goto on_error;
			}
			key = NULL;
		}
		else
		{
			byte_stream_copy_to_uint32_little_endian(
			 page_value_data,
			 child_page_number );

			page_value_data += 4;
			page_value_size -= 4;

#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: page value: %03" PRIu16 " child page number\t\t: %" PRIu32 "",
				 function,
				 page_value_index,
				 child_page_number );

				if( child_page_number == 0 )
				{
					libcnotify_printf(
					 " (invalid page number)\n" );
				}
				else if( child_page_number > page_tree->io_handle->last_page_number )
				{
					libcnotify_printf(
					 " (exceeds last page number: %" PRIu32 ")\n",
					 page_tree->io_handle->last_page_number );
				}
				libcnotify_printf(
				 "\n" );
				libcnotify_printf(
				 "\n" );
			}
#endif
#if defined( HAVE_DEBUG_OUTPUT )
			if( ( libcnotify_verbose != 0 )
			 && ( page_value_size > 0 ) )
			{
				libcnotify_printf(
				 "%s: page value: %03" PRIu16 " trailing data:\n",
				 function,
				 page_value_index );
				libcnotify_print_data(
				 page_value_data,
				 page_value_size,
				 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
			}
#endif
			if( ( child_page_number > 0 )
			 && ( child_page_number <= page_tree->io_handle->last_page_number ) )
			{
				sub_node_data_offset  = child_page_number - 1;
				sub_node_data_offset *= page_tree->io_handle->page_size;

				key->type = LIBESEDB_KEY_TYPE_BRANCH;

				if( libfdata_btree_node_append_sub_node(
				     node,
				     &element_index,
				     0,
				     sub_node_data_offset,
				     (size64_t) page_tree->io_handle->page_size,
				     0,
				     (intptr_t *) key,
				     (int (*)(intptr_t **, libcerror_error_t **)) &libesedb_key_free,
				     LIBFDATA_KEY_VALUE_FLAG_MANAGED,
				     error ) != 1 )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
					 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
					 "%s: unable to append page: %" PRIu32 " value: %" PRIu16 " as sub node.",
					 function,
					 page_number,
					 page_value_index );

					goto on_error;
				}
				key = NULL;
			}
		}
		if( key != NULL )
		{
			if( libesedb_key_free(
			     &key,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
				 "%s: unable to free key.",
				 function );

				goto on_error;
			}
		}
	}
	return( 1 );

on_error:
	if( key != NULL )
	{
		libesedb_key_free(
		 &key,
		 NULL );
	}
	return( -1 );
}
/* Reads the root page
 * Returns 1 if successful or -1 on error
 */
int libesedb_page_tree_read_root_page(
     libesedb_page_tree_t *page_tree,
     libbfio_handle_t *file_io_handle,
     off64_t page_offset,
     uint32_t page_number,
     libcerror_error_t **error )
{
	libesedb_page_t *page             = NULL;
	libesedb_page_value_t *page_value = NULL;
	static char *function             = "libesedb_page_tree_read_root_page";
	off64_t element_data_offset       = 0;
	uint32_t extent_space             = 0;
	uint32_t required_flags           = 0;
	uint32_t supported_flags          = 0;
	uint32_t space_tree_page_number   = 0;
	uint16_t number_of_page_values    = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	uint32_t initial_number_of_pages  = 0;
	uint32_t value_32bit              = 0;
#endif

	if( page_tree == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid page tree.",
		 function );

		return( -1 );
	}
	if( libfdata_vector_get_element_value_at_offset(
	     page_tree->pages_vector,
	     (intptr_t *) file_io_handle,
	     page_tree->pages_cache,
	     page_offset,
	     &element_data_offset,
	     (intptr_t **) &page,
	     0,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve page: %" PRIu32 " at offset: 0x%08" PRIx64 ".",
		 function,
		 page_number,
		 page_offset );

		return( -1 );
	}
	if( page == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: missing page.",
		 function );

		return( -1 );
	}
	required_flags = LIBESEDB_PAGE_FLAG_IS_ROOT;

	if( ( page->flags & required_flags ) != required_flags )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: missing required page flags: 0x%08" PRIx32 ".",
		 function,
		 page->flags );

		return( -1 );
	}
	if( ( page->flags & LIBESEDB_PAGE_FLAG_IS_EMPTY ) != 0 )
	{
		return( 1 );
	}
	supported_flags = required_flags
	                | LIBESEDB_PAGE_FLAG_IS_LEAF
	                | LIBESEDB_PAGE_FLAG_IS_PARENT
	                | LIBESEDB_PAGE_FLAG_IS_INDEX
	                | LIBESEDB_PAGE_FLAG_IS_SPACE_TREE
	                | LIBESEDB_PAGE_FLAG_IS_LONG_VALUE
	                | LIBESEDB_PAGE_FLAG_0x0400
	                | LIBESEDB_PAGE_FLAG_0x0800
	                | LIBESEDB_PAGE_FLAG_IS_NEW_RECORD_FORMAT
	                | LIBESEDB_PAGE_FLAG_IS_SCRUBBED
	                | LIBESEDB_PAGE_FLAG_0x8000;

	if( ( page->flags & ~supported_flags ) != 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported page flags: 0x%08" PRIx32 ".",
		 function,
		 page->flags );

		return( -1 );
	}
	if( libesedb_page_get_number_of_values(
	     page,
	     &number_of_page_values,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve number of page values.",
		 function );

		return( -1 );
	}
	if( number_of_page_values == 0 )
	{
		return( 1 );
	}
	if( libesedb_page_get_value(
	     page,
	     0,
	     &page_value,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve page value: 0.",
		 function );

		return( -1 );
	}
	if( page_value == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: missing page value.",
		 function );

		return( -1 );
	}
	if( page_value->data == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: invalid page value - missing data.",
		 function );

		return( -1 );
	}
	if( page_value->size != 16 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported size of page value.",
		 function );

		return( -1 );
	}
	byte_stream_copy_to_uint32_little_endian(
	 ( (esedb_root_page_header_t *) page_value->data )->space_tree_page_number,
	 space_tree_page_number );

/* TODO handle the root page header */

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_root_page_header_t *) page_value->data )->initial_number_of_pages,
		 initial_number_of_pages );
		libcnotify_printf(
		 "%s: (header) initial number of pages\t: %" PRIu32 "\n",
		 function,
		 initial_number_of_pages );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_root_page_header_t *) page_value->data )->parent_father_data_page_number,
		 value_32bit );
		libcnotify_printf(
		 "%s: (header) parent FDP number\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_root_page_header_t *) page_value->data )->extent_space,
		 extent_space );
		libcnotify_printf(
		 "%s: (header) extent space\t\t: %" PRIu32 "\n",
		 function,
		 extent_space );

		libcnotify_printf(
		 "%s: (header) space tree page number\t: %" PRIu32 " (0x%08" PRIx32 ")\n",
		 function,
		 space_tree_page_number,
		 space_tree_page_number );

		libcnotify_printf(
		 "%s: (header) primary extent\t\t: %" PRIu32 "-%c\n",
		 function,
		 initial_number_of_pages,
		 ( extent_space == 0 ? 's' : 'm' ) );

		libcnotify_printf(
		 "\n" );
	}
#endif
	/* Read the space tree pages
	 */
	if( extent_space > 0 )
	{
		if( space_tree_page_number >= 0xff000000UL )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
			 "%s: unsupported space tree page number.",
			 function,
			 space_tree_page_number );

			return( -1 );
		}
		if( space_tree_page_number > 0 )
		{
			/* Read the owned pages space tree page
			 */
			if( libesedb_page_tree_read_space_tree_page(
			     page_tree,
			     file_io_handle,
			     space_tree_page_number,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_IO,
				 LIBCERROR_IO_ERROR_READ_FAILED,
				 "%s: unable to read space tree page: %" PRIu32 ".",
				 function,
				 space_tree_page_number );

				return( -1 );
			}
			/* Read the available pages space tree page
			 */
			space_tree_page_number += 1;

			if( libesedb_page_tree_read_space_tree_page(
			     page_tree,
			     file_io_handle,
			     space_tree_page_number,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_IO,
				 LIBCERROR_IO_ERROR_READ_FAILED,
				 "%s: unable to read space tree page: %" PRIu32 ".",
				 function,
				 space_tree_page_number );

				return( -1 );
			}
		}
	}
	return( 1 );
}
/* Reads an allocation table
 * Returns 1 if successful or -1 on error
 */
int libpff_allocation_table_read(
     libcdata_range_list_t *unallocated_block_list,
     libbfio_handle_t *file_io_handle,
     off64_t allocation_table_offset,
     uint8_t file_type,
     libcerror_error_t **error )
{
	uint8_t *allocation_table_data     = NULL;
	uint8_t *table_data                = NULL;
	static char *function              = "libpff_allocation_table_read";
	off64_t back_pointer_offset        = 0;
	off64_t unallocated_offset         = 0;
	size_t read_size                   = 0;
	size_t unallocated_size            = 0;
	size_t allocation_block_size       = 0;
	ssize_t read_count                 = 0;
	uint32_t stored_checksum           = 0;
	uint32_t calculated_checksum       = 0;
	uint16_t table_data_index          = 0;
	uint16_t table_data_size           = 0;
	uint8_t allocation_table_entry     = 0;
	uint8_t allocation_table_type      = 0;
	uint8_t allocation_table_type_copy = 0;
	uint8_t bit_index                  = 0;

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

	if( unallocated_block_list == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid unallocated block list.",
		 function );

		return( -1 );
	}
	if( file_io_handle == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid file IO handle.",
		 function );

		return( -1 );
	}
	if( ( file_type != LIBPFF_FILE_TYPE_32BIT )
	 && ( file_type != LIBPFF_FILE_TYPE_64BIT )
	 && ( file_type != LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported file type.",
		 function );

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

		goto on_error;
	}
	if( file_type == LIBPFF_FILE_TYPE_32BIT )
	{
		read_size       = sizeof( pff_allocation_table_32bit_t );
		table_data_size = 496;
	}
	else if( file_type == LIBPFF_FILE_TYPE_64BIT )
	{
		read_size       = sizeof( pff_allocation_table_64bit_t );
		table_data_size = 496;
	}
	else if( file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE )
	{
		read_size       = sizeof( pff_allocation_table_64bit_4k_page_t );
		table_data_size = 4072;
	}
	allocation_table_data = (uint8_t *) memory_allocate(
	                                     sizeof( uint8_t ) * read_size );

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

		goto on_error;
	}
	read_count = libbfio_handle_read_buffer(
	              file_io_handle,
	              allocation_table_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 allocation table.",
		 function );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: allocation table:\n",
		 function );
		libcnotify_print_data(
		 allocation_table_data,
		 read_size,
		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
	}
#endif
	if( file_type == LIBPFF_FILE_TYPE_32BIT )
	{
		table_data                 = ( (pff_allocation_table_32bit_t *) allocation_table_data )->data;
		allocation_table_type      = ( (pff_allocation_table_32bit_t *) allocation_table_data )->type;
		allocation_table_type_copy = ( (pff_allocation_table_32bit_t *) allocation_table_data )->type_copy;

		byte_stream_copy_to_uint32_little_endian(
		 ( (pff_allocation_table_32bit_t *) allocation_table_data )->back_pointer,
		 back_pointer_offset );
		byte_stream_copy_to_uint32_little_endian(
		 ( (pff_allocation_table_32bit_t *) allocation_table_data )->checksum,
		 stored_checksum );
	}
	else if( file_type == LIBPFF_FILE_TYPE_64BIT )
	{
		table_data                 = ( (pff_allocation_table_64bit_t *) allocation_table_data )->data;
		allocation_table_type      = ( (pff_allocation_table_64bit_t *) allocation_table_data )->type;
		allocation_table_type_copy = ( (pff_allocation_table_64bit_t *) allocation_table_data )->type_copy;

		byte_stream_copy_to_uint32_little_endian(
		 ( (pff_allocation_table_64bit_t *) allocation_table_data )->checksum,
		 stored_checksum );
		byte_stream_copy_to_uint64_little_endian(
		 ( (pff_allocation_table_64bit_t *) allocation_table_data )->back_pointer,
		 back_pointer_offset );
	}
	else if( file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE )
	{
		table_data                 = ( (pff_allocation_table_64bit_4k_page_t *) allocation_table_data )->data;
		allocation_table_type      = ( (pff_allocation_table_64bit_4k_page_t *) allocation_table_data )->type;
		allocation_table_type_copy = ( (pff_allocation_table_64bit_4k_page_t *) allocation_table_data )->type_copy;

		byte_stream_copy_to_uint32_little_endian(
		 ( (pff_allocation_table_64bit_4k_page_t *) allocation_table_data )->checksum,
		 stored_checksum );
		byte_stream_copy_to_uint64_little_endian(
		 ( (pff_allocation_table_64bit_4k_page_t *) allocation_table_data )->back_pointer,
		 back_pointer_offset );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: type\t\t: 0x%02" PRIx8 "\n",
		 function,
		 allocation_table_type );
		libcnotify_printf(
		 "%s: type copy\t\t: 0x%02" PRIx8 "\n",
		 function,
		 allocation_table_type_copy );

		if( file_type == LIBPFF_FILE_TYPE_32BIT )
		{
			byte_stream_copy_to_uint16_little_endian(
			 ( (pff_allocation_table_32bit_t *) allocation_table_data )->signature,
			 value_16bit );
			libcnotify_printf(
			 "%s: signature\t\t: 0x%04" PRIx16 "\n",
			 function,
			 value_16bit );

			libcnotify_printf(
			 "%s: back pointer\t: %" PRIu64 "\n",
			 function,
			 back_pointer_offset );

			libcnotify_printf(
			 "%s: checksum\t\t: 0x%" PRIx32 "\n",
			 function,
			 stored_checksum );
		}
		else if( ( file_type == LIBPFF_FILE_TYPE_64BIT )
		      || ( file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
		{
			if( file_type == LIBPFF_FILE_TYPE_64BIT )
			{
				byte_stream_copy_to_uint16_little_endian(
				 ( (pff_allocation_table_64bit_t *) allocation_table_data )->signature,
				 value_16bit );
			}
			else
			{
				byte_stream_copy_to_uint16_little_endian(
				 ( (pff_allocation_table_64bit_4k_page_t *) allocation_table_data )->signature,
				 value_16bit );
			}
			libcnotify_printf(
			 "%s: signature\t\t: 0x%04" PRIx16 "\n",
			 function,
			 value_16bit );

			libcnotify_printf(
			 "%s: checksum\t\t: 0x%" PRIx32 "\n",
			 function,
			 stored_checksum );

			libcnotify_printf(
			 "%s: back pointer\t: %" PRIu64 "\n",
			 function,
			 back_pointer_offset );

			if( file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE )
			{
				byte_stream_copy_to_uint64_little_endian(
				 ( (pff_allocation_table_64bit_4k_page_t *) allocation_table_data )->unknown1,
				 value_64bit );
				libcnotify_printf(
				 "%s: unknown1\t\t: 0x%08" PRIx64 "\n",
				 function,
				 value_64bit );
			}
		}
		libcnotify_printf(
		 "\n" );
	}
#endif
	if( libfmapi_checksum_calculate_weak_crc32(
	     &calculated_checksum,
	     table_data,
	     (size_t) table_data_size,
	     0,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
		 "%s: unable to calculate weak CRC-32.",
		 function );

		goto on_error;
	}
	if( stored_checksum != calculated_checksum )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_INPUT,
		 LIBCERROR_INPUT_ERROR_CHECKSUM_MISMATCH,
		 "%s: mismatch in checksum ( %" PRIu32 " != %" PRIu32 " ).",
		 function,
		 stored_checksum,
		 calculated_checksum );

/* TODO implement error tollerance */
		goto on_error;
	}
	if( allocation_table_type != allocation_table_type_copy )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_INPUT,
		 LIBCERROR_INPUT_ERROR_CHECKSUM_MISMATCH,
		 "%s: mismatch in allocation table type ( 0x%02" PRIx8 " != 0x%02" PRIx8 " ).",
		 function,
		 allocation_table_type,
		 allocation_table_type_copy );

/* TODO implement error tollerance */
		goto on_error;
	}
	if( ( allocation_table_type != LIBPFF_ALLOCATION_TABLE_TYPE_DATA )
	 && ( allocation_table_type != LIBPFF_ALLOCATION_TABLE_TYPE_PAGE ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported allocation table type: 0x%08" PRIx32 "",
		 function,
		 allocation_table_type );

/* TODO implement error tollerance */
		goto on_error;
	}
	if( allocation_table_type == LIBPFF_ALLOCATION_TABLE_TYPE_PAGE )
	{
		/* The page type allocation has not yet been seen i.c.w. 4k pages */
		if( file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
			 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
			 "%s: unsupported file type.",
			 function );

			goto on_error;
		}
		allocation_block_size = 512;
		back_pointer_offset  -= 0x200;
	}
	else if( allocation_table_type == LIBPFF_ALLOCATION_TABLE_TYPE_DATA )
	{
		allocation_block_size = 64;
	}
	for( table_data_index = 0;
	     table_data_index < table_data_size;
	     table_data_index++ )
	{
		allocation_table_entry = table_data[ table_data_index ];

		for( bit_index = 0;
		     bit_index < 8;
		     bit_index++ )
		{
			if( ( allocation_table_entry & 0x80 ) == 0 )
			{
				if( unallocated_size == 0 )
				{
					unallocated_offset = back_pointer_offset;
				}
				unallocated_size += allocation_block_size;
			}
			else if( unallocated_size > 0 )
			{
#if defined( HAVE_DEBUG_OUTPUT )
				if( libcnotify_verbose != 0 )
				{
					libcnotify_printf(
					 "%s: unallocated block: 0x%08" PRIx64 " - 0x%08" PRIx64 " (%" PRIu64 ")\n",
					 function,
					 unallocated_offset,
					 unallocated_offset + unallocated_size,
					 unallocated_size );
				}
#endif
				if( libcdata_range_list_insert_range(
				     unallocated_block_list,
				     unallocated_offset,
				     unallocated_size,
				     NULL,
				     NULL,
				     NULL,
				     error ) != 1 )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
					 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
					 "%s: unable to append unallocated block to list.",
					 function );

					goto on_error;
				}
				unallocated_size = 0;
			}
			allocation_table_entry <<= 1;

			back_pointer_offset += allocation_block_size;
		}
	}
	if( unallocated_size > 0 )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: unallocated block: 0x%08" PRIx64 " - 0x%08" PRIx64 " (%" PRIu64 ")\n",
			 function,
			 unallocated_offset,
			 unallocated_offset + unallocated_size,
			 unallocated_size );
		}
#endif
		if( libcdata_range_list_insert_range(
		     unallocated_block_list,
		     unallocated_offset,
		     unallocated_size,
		     NULL,
		     NULL,
		     NULL,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
			 "%s: unable to append unallocated block to list.",
			 function );

			goto on_error;
		}
		unallocated_size = 0;
	}
	memory_free(
	 allocation_table_data );

	return( 1 );

on_error:
	if( allocation_table_data != NULL )
	{
		memory_free(
		 allocation_table_data );
	}
	return( -1 );
}
/* Converts an access control entry stored in a byte stream into a runtime version
 * Returns 1 if successful or -1 on error
 */
int libfwnt_access_control_entry_copy_from_byte_stream(
     libfwnt_access_control_entry_t *access_control_entry,
     const uint8_t *byte_stream,
     size_t byte_stream_size,
     int byte_order,
     libcerror_error_t **error )
{
	libfwnt_internal_access_control_entry_t *internal_access_control_entry = NULL;
	static char *function                                                  = "libfwnt_access_control_entry_copy_from_byte_stream";
	size_t access_mask_offset                                              = 0;
	size_t sid_offset                                                      = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	system_character_t *sid_string                                         = NULL;
	size_t sid_string_size                                                 = 0;
	int result                                                             = 0;
#endif

	if( access_control_entry == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid access control entry.",
		 function );

		return( -1 );
	}
	internal_access_control_entry = (libfwnt_internal_access_control_entry_t *) access_control_entry;

	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 < 4 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
		 "%s: byte stream too small.",
		 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: byte stream size exceeds maximum.",
		 function );

		return( -1 );
	}
	if( byte_order != LIBFWNT_ENDIAN_LITTLE )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported byte order.",
		 function );

		return( -1 );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: header data:\n",
		 function );
		libcnotify_print_data(
		 byte_stream,
		 4,
		 0 );
	}
#endif
	internal_access_control_entry->type  = byte_stream[ 0 ];
	internal_access_control_entry->flags = byte_stream[ 1 ];

	byte_stream_copy_to_uint16_little_endian(
	 &( byte_stream[ 2 ] ),
	 internal_access_control_entry->size );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: type\t\t: %" PRIu8 " (%s)\n",
		 function,
		 internal_access_control_entry->type,
		 libfwnt_debug_print_access_control_entry_type(
		  internal_access_control_entry->type ) );

		libcnotify_printf(
		 "%s: flags\t\t: 0x%02" PRIx8 "\n",
		 function,
		 internal_access_control_entry->flags );
		libfwnt_debug_print_access_control_entry_flags(
		 internal_access_control_entry->flags );
		libcnotify_printf(
		 "\n" );

		libcnotify_printf(
		 "%s: size\t\t: %" PRIu16 "\n",
		 function,
		 internal_access_control_entry->size );

		libcnotify_printf(
		 "\n" );
	}
#endif
	if( ( internal_access_control_entry->size < 4 )
	 || ( (size_t) internal_access_control_entry->size > byte_stream_size ) )

	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
		 "%s: access control entry size value out of bounds.",
		 function );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: access control entry data:\n",
		 function );
		libcnotify_print_data(
		 &( byte_stream[ 4 ] ),
		 internal_access_control_entry->size - 4,
		 0 );
	}
#endif
	switch( internal_access_control_entry->type )
	{
		/* Basic types */
		case LIBFWNT_ACCESS_ALLOWED:
		case LIBFWNT_ACCESS_DENIED:
		case LIBFWNT_SYSTEM_AUDIT:
		case LIBFWNT_SYSTEM_ALARM:
		case LIBFWNT_ACCESS_ALLOWED_CALLBACK:
		case LIBFWNT_ACCESS_DENIED_CALLBACK:
		case LIBFWNT_SYSTEM_AUDIT_CALLBACK:
		case LIBFWNT_SYSTEM_ALARM_CALLBACK:
		case LIBFWNT_SYSTEM_MANDATORY_LABEL:
			access_mask_offset = 4;
			sid_offset         = 8;
			break;

		/* Object types */
		case LIBFWNT_ACCESS_ALLOWED_OBJECT:
		case LIBFWNT_ACCESS_DENIED_OBJECT:
		case LIBFWNT_SYSTEM_AUDIT_OBJECT:
		case LIBFWNT_SYSTEM_ALARM_OBJECT:
		case LIBFWNT_ACCESS_ALLOWED_CALLBACK_OBJECT:
		case LIBFWNT_ACCESS_DENIED_CALLBACK_OBJECT:
		case LIBFWNT_SYSTEM_AUDIT_CALLBACK_OBJECT:
		case LIBFWNT_SYSTEM_ALARM_CALLBACK_OBJECT:
			access_mask_offset = 4;
			sid_offset         = 40;
			break;

		/* Unknown types */
		case LIBFWNT_ACCESS_ALLOWED_COMPOUND:
		default:
			break;
	}
	if( access_mask_offset > 0 )
	{
		byte_stream_copy_to_uint32_little_endian(
		 &( byte_stream[ access_mask_offset ] ),
		 internal_access_control_entry->access_mask );

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: access mask\t\t: 0x%08" PRIx32 "\n",
			 function,
			 internal_access_control_entry->access_mask );
			libfwnt_debug_print_access_control_entry_access_mask(
			 internal_access_control_entry->access_mask );
			libcnotify_printf(
			 "\n" );
		}
#endif
	}
	if( sid_offset > 0 )
	{
		if( sid_offset > byte_stream_size )

		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: security identifier offset value out of bounds.",
			 function );

			goto on_error;
		}
		if( libfwnt_security_identifier_initialize(
		     &( internal_access_control_entry->security_identifier ),
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
			 "%s: unable to create security identifier.",
			 function );

			goto on_error;
		}
		if( internal_access_control_entry->security_identifier == NULL )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
			 "%s: invalid access control entry - missing owner security identifier.",
			 function );

			goto on_error;
		}
		( (libfwnt_internal_security_identifier_t *) internal_access_control_entry->security_identifier )->is_managed = 1;

		if( libfwnt_security_identifier_copy_from_byte_stream(
		     internal_access_control_entry->security_identifier,
		     &( byte_stream[ sid_offset ] ),
		     byte_stream_size - sid_offset,
		     byte_order,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
			 "%s: unable to copy security identifier from byte stream.",
			 function );

			goto on_error;
		}
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			if( libfwnt_security_identifier_get_string_size(
			     internal_access_control_entry->security_identifier,
			     &sid_string_size,
			     0,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
				 "%s: unable to retrieve security identifier string size.",
				 function );

				goto on_error;
			}
			libcnotify_printf(
			 "%s: SID\t\t\t: ",
			 function );

			if( sid_string_size > 0 )
			{
				sid_string = system_string_allocate(
					      sid_string_size );

				if( sid_string == NULL )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_MEMORY,
					 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
					 "%s: unable to create security identifier string.",
					 function );

					goto on_error;
				}
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
				result = libfwnt_security_identifier_copy_to_utf16_string(
					  internal_access_control_entry->security_identifier,
					  (uint16_t *) sid_string,
					  sid_string_size,
					  0,
					  error );
#else
				result = libfwnt_security_identifier_copy_to_utf8_string(
					  internal_access_control_entry->security_identifier,
					  (uint8_t *) sid_string,
					  sid_string_size,
					  0,
					  error );
#endif
				if( result != 1 )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
					 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
					 "%s: unable to copy security identifier to string.",
					 function );

					goto on_error;
				}
				libcnotify_printf(
				 "%" PRIs_SYSTEM "",
				 sid_string );

				memory_free(
				 sid_string );

				sid_string = NULL;
			}
			libcnotify_printf(
			 "\n" );
		}
#endif
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "\n" );
	}
#endif
	return( 1 );

on_error:
#if defined( HAVE_DEBUG_OUTPUT )
	if( sid_string != NULL )
	{
		memory_free(
		 sid_string );
	}
#endif
	if( internal_access_control_entry->security_identifier != NULL )
	{
		libfwnt_internal_security_identifier_free(
		 (libfwnt_internal_security_identifier_t **) &( internal_access_control_entry->security_identifier ),
		 NULL );
	}
	return( -1 );
}
Exemple #14
0
/* Reads an free map
 * Returns 1 if successful or -1 on error
 */
int libpff_free_map_read(
     libcdata_range_list_t *unallocated_block_list,
     libbfio_handle_t *file_io_handle,
     off64_t free_map_offset,
     uint8_t file_type,
     libcerror_error_t **error )
{
	uint8_t *free_map_data       = NULL;
	uint8_t *table_data          = NULL;
	static char *function        = "libpff_free_map_read";
	off64_t back_pointer_offset  = 0;
	off64_t unallocated_offset   = 0;
	size_t read_size             = 0;
	size_t unallocated_size      = 0;
	size_t allocation_block_size = 0;
	ssize_t read_count           = 0;
	uint32_t stored_checksum     = 0;
	uint32_t calculated_checksum = 0;
	uint16_t table_iterator      = 0;
	uint8_t bit_iterator         = 0;
	uint8_t free_map_entry       = 0;
	uint8_t free_map_type        = 0;
	uint8_t free_map_type_copy   = 0;
	int result                   = 0;

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

	if( unallocated_block_list == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid unallocated block list.",
		 function );

		return( -1 );
	}
	if( file_io_handle == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid file IO handle.",
		 function );

		return( -1 );
	}
	if( ( file_type != LIBPFF_FILE_TYPE_32BIT )
	 && ( file_type != LIBPFF_FILE_TYPE_64BIT ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported file type.",
		 function );

		return( -1 );
	}
	if( libbfio_handle_seek_offset(
	     file_io_handle,
	     free_map_offset,
	     SEEK_SET,
	     error ) == -1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_SEEK_FAILED,
		 "%s: unable to seek free map offset: %" PRIi64 ".",
		 function,
		 free_map_offset );

		goto on_error;
	}
	if( file_type == LIBPFF_FILE_TYPE_32BIT )
	{
		read_size = sizeof( pff_free_map_32bit_t );
	}
	else if( file_type == LIBPFF_FILE_TYPE_64BIT )
	{
		read_size = sizeof( pff_free_map_64bit_t );
	}
	free_map_data = (uint8_t *) memory_allocate(
	                             sizeof( uint8_t ) * read_size );

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

		goto on_error;
	}
	read_count = libbfio_handle_read_buffer(
	              file_io_handle,
	              free_map_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 free map.",
		 function );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: free map:\n",
		 function );
		libcnotify_print_data(
		 free_map_data,
		 read_size,
		 0 );
	}
#endif
	if( file_type == LIBPFF_FILE_TYPE_32BIT )
	{
		table_data         = ( (pff_free_map_32bit_t *) free_map_data )->data;
		free_map_type      = ( (pff_free_map_32bit_t *) free_map_data )->type;
		free_map_type_copy = ( (pff_free_map_32bit_t *) free_map_data )->type_copy;

		byte_stream_copy_to_uint32_little_endian(
		 ( (pff_free_map_32bit_t *) free_map_data )->back_pointer,
		 back_pointer_offset );
		byte_stream_copy_to_uint32_little_endian(
		 ( (pff_free_map_32bit_t *) free_map_data )->checksum,
		 stored_checksum );
	}
	else if( file_type == LIBPFF_FILE_TYPE_64BIT )
	{
		table_data         = ( (pff_free_map_64bit_t *) free_map_data )->data;
		free_map_type      = ( (pff_free_map_64bit_t *) free_map_data )->type;
		free_map_type_copy = ( (pff_free_map_64bit_t *) free_map_data )->type_copy;

		byte_stream_copy_to_uint32_little_endian(
		 ( (pff_free_map_64bit_t *) free_map_data )->checksum,
		 stored_checksum );
		byte_stream_copy_to_uint64_little_endian(
		 ( (pff_free_map_64bit_t *) free_map_data )->back_pointer,
		 back_pointer_offset );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: type\t\t: 0x%02" PRIx8 "\n",
		 function,
		 free_map_type );
		libcnotify_printf(
		 "%s: type copy\t: 0x%02" PRIx8 "\n",
		 function,
		 free_map_type_copy );

		if( file_type == LIBPFF_FILE_TYPE_32BIT )
		{
			byte_stream_copy_to_uint16_little_endian(
			 ( (pff_free_map_32bit_t *) free_map_data )->signature,
			 value_16bit );
			libcnotify_printf(
			 "%s: signature\t: 0x%04" PRIx16 "\n",
			 function,
			 value_16bit );

			libcnotify_printf(
			 "%s: back pointer\t: %" PRIu64 "\n",
			 function,
			 back_pointer_offset );

			libcnotify_printf(
			 "%s: checksum\t: 0x%" PRIx32 "\n",
			 function,
			 stored_checksum );
		}
		else if( file_type == LIBPFF_FILE_TYPE_64BIT )
		{
			byte_stream_copy_to_uint16_little_endian(
			 ( (pff_free_map_64bit_t *) free_map_data )->signature,
			 value_16bit );
			libcnotify_printf(
			 "%s: signature\t: 0x%04" PRIx16 "\n",
			 function,
			 value_16bit );

			libcnotify_printf(
			 "%s: checksum\t\t: 0x%" PRIx32 "\n",
			 function,
			 stored_checksum );

			libcnotify_printf(
			 "%s: back pointer\t: %" PRIu64 "\n",
			 function,
			 back_pointer_offset );
		}
		libcnotify_printf(
		 "\n" );
	}
#endif

	if( libfmapi_checksum_calculate_weak_crc32(
	     &calculated_checksum,
	     table_data,
	     496,
	     0,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
		 "%s: unable to calculate weak CRC-32.",
		 function );

		goto on_error;
	}
	if( stored_checksum != calculated_checksum )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_INPUT,
		 LIBCERROR_INPUT_ERROR_CHECKSUM_MISMATCH,
		 "%s: mismatch in checksum ( %" PRIu32 " != %" PRIu32 " ).",
		 function,
		 stored_checksum,
		 calculated_checksum );

		/* TODO implement error tollerance
		 */
		goto on_error;
	}
	if( free_map_type != free_map_type_copy )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_INPUT,
		 LIBCERROR_INPUT_ERROR_CHECKSUM_MISMATCH,
		 "%s: mismatch in allocation table type ( 0x%02" PRIx8 " != 0x%02" PRIx8 " ).",
		 function,
		 free_map_type,
		 free_map_type_copy );

		/* TODO implement error tollerance
		 */
		goto on_error;
	}
	if( ( free_map_type != LIBPFF_FREE_MAP_TYPE_DATA )
	 && ( free_map_type != LIBPFF_FREE_MAP_TYPE_PAGE ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported allocation table type: 0x%08" PRIx32 "",
		 function,
		 free_map_type );

		/* TODO implement error tollerance
		 */
		goto on_error;
	}
	/* TODO */
	if( free_map_type == LIBPFF_FREE_MAP_TYPE_PAGE )
	{
		allocation_block_size = 512;
		back_pointer_offset  -= 0x200;
	}
	else if( free_map_type == LIBPFF_FREE_MAP_TYPE_DATA )
	{
		allocation_block_size = 64;
	}
	for( table_iterator = 0;
	     table_iterator < 496;
	     table_iterator++ )
	{
		free_map_entry = table_data[ table_iterator ];

		for( bit_iterator = 0;
		     bit_iterator < 8;
		     bit_iterator++ )
		{
			if( ( free_map_entry & 0x80 ) == 0 )
			{
				if( unallocated_size == 0 )
				{
					unallocated_offset = back_pointer_offset;
				}
				unallocated_size += allocation_block_size;
			}
			else if( unallocated_size > 0 )
			{
				result = libcdata_range_list_insert_range(
				          unallocated_block_list,
				          unallocated_offset,
				          unallocated_size,
				          NULL,
				          NULL,
				          NULL,
				          error );

				if( result == -1 )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
					 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
					 "%s: unable to append unallocated block to list.",
					 function );

					goto on_error;
				}
				unallocated_size = 0;
			}
			free_map_entry <<= 1;

			back_pointer_offset += allocation_block_size;
		}
	}
	if( unallocated_size > 0 )
	{
		result = libcdata_range_list_insert_range(
		          unallocated_block_list,
		          unallocated_offset,
		          unallocated_size,
		          NULL,
		          NULL,
		          NULL,
		          error );

		if( result == -1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
			 "%s: unable to append unallocated block to list.",
			 function );

			goto on_error;
		}
		unallocated_size = 0;
	}
	memory_free(
	 free_map_data );

	return( 1 );

on_error:
	if( free_map_data != NULL )
	{
		memory_free(
		 free_map_data );
	}
	return( -1 );
}
/* Reads the level 1 metadata
 * Returns 1 if successful or -1 on error
 */
int libfsrefs_level1_metadata_read(
     libfsrefs_level1_metadata_t *level1_metadata,
     libfsrefs_io_handle_t *io_handle,
     libbfio_handle_t *file_io_handle,
     off64_t file_offset,
     libcerror_error_t **error )
{
	libfsrefs_block_descriptor_t *block_descriptor = NULL;
	libfsrefs_metadata_block_t *metadata_block     = NULL;
	static char *function                          = "libfsrefs_level1_metadata_read";
	size_t metadata_block_data_offset              = 0;
	uint32_t entry_index                           = 0;
	uint32_t entry_offset                          = 0;
	uint32_t number_of_entries                     = 0;
	int array_entry_index                          = 0;

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

	if( level1_metadata == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid level 1 metadata.",
		 function );

		return( -1 );
	}
	if( libfsrefs_metadata_block_initialize(
	     &metadata_block,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
		 "%s: unable to create metadata block.",
		 function );

		goto on_error;
	}
	if( libfsrefs_metadata_block_read(
	     metadata_block,
	     io_handle,
	     file_io_handle,
	     file_offset,
	     1,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_READ_FAILED,
		 "%s: unable to read metadata block.",
		 function );

		goto on_error;
	}
	if( metadata_block->data == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: invalid metadata block - missing data.",
		 function );

		goto on_error;
	}
	level1_metadata->sequence_number = metadata_block->sequence_number;

/* TODO add structures */
	byte_stream_copy_to_uint32_little_endian(
	 &( metadata_block->data[ 56 ] ),
	 entry_offset );

	byte_stream_copy_to_uint32_little_endian(
	 &( metadata_block->data[ 88 ] ),
	 number_of_entries );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		byte_stream_copy_to_uint32_little_endian(
		 &( metadata_block->data[ 48 ] ),
		 value_32bit );
		libcnotify_printf(
		 "%s: unknown1\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint16_little_endian(
		 &( metadata_block->data[ 52 ] ),
		 value_16bit );
		libcnotify_printf(
		 "%s: unknown2\t\t\t\t: 0x%04" PRIx16 "\n",
		 function,
		 value_16bit );

		byte_stream_copy_to_uint16_little_endian(
		 &( metadata_block->data[ 54 ] ),
		 value_16bit );
		libcnotify_printf(
		 "%s: unknown3\t\t\t\t: 0x%04" PRIx16 "\n",
		 function,
		 value_16bit );

		libcnotify_printf(
		 "%s: unknown4 offset\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 entry_offset );

		byte_stream_copy_to_uint32_little_endian(
		 &( metadata_block->data[ 60 ] ),
		 value_32bit );
		libcnotify_printf(
		 "%s: table entry size\t\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint64_little_endian(
		 &( metadata_block->data[ 64 ] ),
		 value_64bit );
		libcnotify_printf(
		 "%s: sequence number\t\t\t\t: %" PRIu64 "\n",
		 function,
		 value_64bit );

		byte_stream_copy_to_uint32_little_endian(
		 &( metadata_block->data[ 72 ] ),
		 value_32bit );
		libcnotify_printf(
		 "%s: unknown5\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 &( metadata_block->data[ 76 ] ),
		 value_32bit );
		libcnotify_printf(
		 "%s: unknown6\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		libcnotify_printf(
		 "%s: unknown7:\n",
		 function );
		libcnotify_print_data(
		 &( metadata_block->data[ 80 ] ),
		 8,
		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );

		libcnotify_printf(
		 "%s: number of table entries\t\t\t: %" PRIu32 "\n",
		 function,
		 number_of_entries );

		libcnotify_printf(
		 "%s: table entry offsets data:\n",
		 function );
		libcnotify_print_data(
		 &( metadata_block->data[ 92 ] ),
		 4 * number_of_entries,
		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
	}
#endif
/* TODO check if entry offset is in bounds */

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		byte_stream_copy_to_uint64_little_endian(
		 &( metadata_block->data[ entry_offset ] ),
		 value_64bit );
		libcnotify_printf(
		 "%s: self entry: block number\t\t: %" PRIu64 "\n",
		 function,
		 value_64bit );

		byte_stream_copy_to_uint64_little_endian(
		 &( metadata_block->data[ entry_offset + 8 ] ),
		 value_64bit );
		libcnotify_printf(
		 "%s: self entry: unknown1\t\t\t: 0x%08" PRIx64 "\n",
		 function,
		 value_64bit );

		byte_stream_copy_to_uint64_little_endian(
		 &( metadata_block->data[ entry_offset + 16 ] ),
		 value_64bit );
		libcnotify_printf(
		 "%s: self entry: checksum\t\t\t: 0x%08" PRIx64 "\n",
		 function,
		 value_64bit );

		libcnotify_printf(
		 "\n" );
	}
#endif
	metadata_block_data_offset = 92;

	for( entry_index = 0;
	     entry_index < number_of_entries;
	     entry_index++ )
	{
		byte_stream_copy_to_uint32_little_endian(
		 &( metadata_block->data[ metadata_block_data_offset ] ),
		 entry_offset );

		metadata_block_data_offset += 4;

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: entry: %02" PRIu32 " offset\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 entry_index,
			 entry_offset );
		}
#endif
		if( libfsrefs_block_descriptor_initialize(
		     &block_descriptor,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
			 "%s: unable to create block descriptor.",
			 function );

			goto on_error;
		}
/* TODO check if entry offset is in bounds */

		byte_stream_copy_to_uint64_little_endian(
		 &( metadata_block->data[ entry_offset ] ),
		 block_descriptor->block_number );

		byte_stream_copy_to_uint64_little_endian(
		 &( metadata_block->data[ entry_offset + 8 ] ),
		 block_descriptor->unknown );

		byte_stream_copy_to_uint64_little_endian(
		 &( metadata_block->data[ entry_offset + 16 ] ),
		 block_descriptor->checksum );

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: entry: %02" PRIu32 " block number\t\t\t: %" PRIu64 "\n",
			 function,
			 entry_index,
			 block_descriptor->block_number );

			libcnotify_printf(
			 "%s: entry: %02" PRIu32 " unknown1\t\t\t: 0x%08" PRIx64 "\n",
			 function,
			 entry_index,
			 block_descriptor->unknown );

			libcnotify_printf(
			 "%s: entry: %02" PRIu32 " checksum\t\t\t: 0x%08" PRIx64 "\n",
			 function,
			 entry_index,
			 block_descriptor->checksum );

			libcnotify_printf(
			 "\n" );
		}
#endif
		if( libcdata_array_append_entry(
		     level1_metadata->level2_metadata_block_descriptors_array,
		     &array_entry_index,
		     (intptr_t *) block_descriptor,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
			 "%s: unable to append block descriptor to array.",
			 function );

			goto on_error;
		}
		block_descriptor = NULL;
	}
	if( libfsrefs_metadata_block_free(
	     &metadata_block,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
		 "%s: unable to free metadata block.",
		 function );

		goto on_error;
	}
	return( 1 );

on_error:
	if( block_descriptor != NULL )
	{
		libfsrefs_block_descriptor_free(
		 &block_descriptor,
		 NULL );
	}
	if( metadata_block != NULL )
	{
		libfsrefs_metadata_block_free(
		 &metadata_block,
		 NULL );
	}
	return( -1 );
}
/* Reads the file (or database) header
 * Returns 1 if successful or -1 on error
 */
int libesedb_io_handle_read_file_header(
     libesedb_io_handle_t *io_handle,
     libbfio_handle_t *file_io_handle,
     off64_t file_offset,
     libcerror_error_t **error )
{
	uint8_t *file_header_data          = NULL;
	static char *function              = "libesedb_io_handle_read_file_header";
	size_t read_size                   = 2048;
	ssize_t read_count                 = 0;
	uint32_t calculated_xor32_checksum = 0;
	uint32_t creation_format_revision  = 0;
	uint32_t creation_format_version   = 0;
	uint32_t format_revision           = 0;
	uint32_t format_version            = 0;
	uint32_t page_size                 = 0;
	uint32_t stored_xor32_checksum     = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	uint32_t value_32bit               = 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 defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: reading file header at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
		 function,
		 file_offset,
		 file_offset );
	}
#endif
	if( libbfio_handle_seek_offset(
	     file_io_handle,
	     file_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: %" PRIi64 ".",
		 function,
		 file_offset );

		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( esedb_file_header_t ),
		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
	}
#endif
	if( memory_compare(
	     ( (esedb_file_header_t *) file_header_data )->signature,
	     esedb_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;
	}
	if( libesedb_checksum_calculate_little_endian_xor32(
	     &calculated_xor32_checksum,
	     &( file_header_data[ 4 ] ),
	     read_size - 4,
	     0x89abcdef,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GENERIC,
		 "%s: unable to calculate XOR-32 checksum.",
		 function );

		goto on_error;
	}
	byte_stream_copy_to_uint32_little_endian(
	 ( (esedb_file_header_t *) file_header_data )->checksum,
	 stored_xor32_checksum );

	if( stored_xor32_checksum != calculated_xor32_checksum )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_INPUT,
		 LIBCERROR_INPUT_ERROR_CHECKSUM_MISMATCH,
		 "%s: mismatch in file header checksum ( 0x%08" PRIx32 " != 0x%08" PRIx32 " ).",
		 function,
		 stored_xor32_checksum,
		 calculated_xor32_checksum );

		goto on_error;
	}
	byte_stream_copy_to_uint32_little_endian(
	 ( (esedb_file_header_t *) file_header_data )->format_version,
	 format_version );

	byte_stream_copy_to_uint32_little_endian(
	 ( (esedb_file_header_t *) file_header_data )->file_type,
	 io_handle->file_type );

	byte_stream_copy_to_uint32_little_endian(
	 ( (esedb_file_header_t *) file_header_data )->format_revision,
	 format_revision );
	byte_stream_copy_to_uint32_little_endian(
	 ( (esedb_file_header_t *) file_header_data )->page_size,
	 page_size );

	byte_stream_copy_to_uint32_little_endian(
	 ( (esedb_file_header_t *) file_header_data )->creation_format_version,
	 creation_format_version );
	byte_stream_copy_to_uint32_little_endian(
	 ( (esedb_file_header_t *) file_header_data )->creation_format_revision,
	 creation_format_revision );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: checksum\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 stored_xor32_checksum );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_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: 0x%08" PRIx32 "\n",
		 function,
		 format_version );

		libcnotify_printf(
		 "%s: file type\t\t\t\t: %" PRIu32 " (",
		 function,
		 io_handle->file_type );
		libesedb_debug_print_file_type(
		 io_handle->file_type );
		libcnotify_printf(
		 ")\n" );

		libcnotify_printf(
		 "%s: database time:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->database_time,
		 8,
		 0 );

		libcnotify_printf(
		 "%s: database signature:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->database_signature,
		 28,
		 0 );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->database_state,
		 value_32bit );
		libcnotify_printf(
		 "%s: database state\t\t\t: %" PRIu32 " ",
		 function,
		 value_32bit );
		libesedb_debug_print_database_state(
		 value_32bit );
		libcnotify_printf(
		 "\n" );

		libcnotify_printf(
		 "%s: consistent position:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->consistent_postition,
		 8,
		 0 );
		libesedb_debug_print_log_time(
		 ( (esedb_file_header_t *) file_header_data )->consistent_time,
		 8,
		 "consistent time",
		 "\t\t\t\t",
		 NULL );

		libesedb_debug_print_log_time(
		 ( (esedb_file_header_t *) file_header_data )->attach_time,
		 8,
		 "attach time",
		 "\t\t\t\t",
		 NULL );
		libcnotify_printf(
		 "%s: attach position:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->attach_postition,
		 8,
		 0 );

		libesedb_debug_print_log_time(
		 ( (esedb_file_header_t *) file_header_data )->detach_time,
		 8,
		 "detach time",
		 "\t\t\t\t",
		 NULL );
		libcnotify_printf(
		 "%s: detach position:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->detach_postition,
		 8,
		 0 );

		libcnotify_printf(
		 "%s: log signature:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->log_signature,
		 28,
		 0 );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->unknown1,
		 value_32bit );
		libcnotify_printf(
		 "%s: unknown1\t\t\t\t: 0x%08" PRIx32 " (%" PRIu32 ")\n",
		 function,
		 value_32bit,
		 value_32bit );

		libcnotify_printf(
		 "%s: previous full backup:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->previous_full_backup,
		 24,
		 0 );
		libcnotify_printf(
		 "%s: previous incremental backup:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->previous_incremental_backup,
		 24,
		 0 );
		libcnotify_printf(
		 "%s: current full backup:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->current_full_backup,
		 24,
		 0 );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->shadowing_disabled,
		 value_32bit );
		libcnotify_printf(
		 "%s: shadowing disabled\t\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->last_object_identifier,
		 value_32bit );
		libcnotify_printf(
		 "%s: last object identifier\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->index_update_major_version,
		 value_32bit );
		libcnotify_printf(
		 "%s: index update major version\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );
		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->index_update_minor_version,
		 value_32bit );
		libcnotify_printf(
		 "%s: index update minor version\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );
		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->index_update_build_number,
		 value_32bit );
		libcnotify_printf(
		 "%s: index update build number\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );
		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->index_update_service_pack_number,
		 value_32bit );
		libcnotify_printf(
		 "%s: index update service pack number\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		libcnotify_printf(
		 "%s: format revision\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 format_revision );
		libcnotify_printf(
		 "%s: page size\t\t\t\t: %" PRIu32 "\n",
		 function,
		 page_size );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->repair_count,
		 value_32bit );
		libcnotify_printf(
		 "%s: repair count\t\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );
		libesedb_debug_print_log_time(
		 ( (esedb_file_header_t *) file_header_data )->repair_time,
		 8,
		 "repair time",
		 "\t\t\t\t",
		 NULL );

		libcnotify_printf(
		 "%s: unknown2:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->unknown2,
		 28,
		 0 );

		libcnotify_printf(
		 "%s: scrub database time:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->scrub_database_time,
		 8,
		 0 );
		libesedb_debug_print_log_time(
		 ( (esedb_file_header_t *) file_header_data )->scrub_time,
		 8,
		 "scrub time",
		 "\t\t\t\t",
		 NULL );

		libcnotify_printf(
		 "%s: required log:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->required_log,
		 8,
		 0 );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->upgrade_exchange5_format,
		 value_32bit );
		libcnotify_printf(
		 "%s: upgrade Exchange 5.5 format\t: %" PRIu32 "\n",
		 function,
		 value_32bit );
		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->upgrade_free_pages,
		 value_32bit );
		libcnotify_printf(
		 "%s: upgrade free pages\t\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );
		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->upgrade_space_map_pages,
		 value_32bit );
		libcnotify_printf(
		 "%s: upgrade space map pages\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		libcnotify_printf(
		 "%s: current shadow volume backup:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->current_shadow_volume_backup,
		 24,
		 0 );

		libcnotify_printf(
		 "%s: creation format version\t\t: 0x%08" PRIx32 "\n",
		 function,
		 creation_format_version );
		libcnotify_printf(
		 "%s: creation format revision\t\t: 0x%08" PRIx32 "\n",
		 function,
		 creation_format_revision );

		libcnotify_printf(
		 "%s: unknown3:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->unknown3,
		 16,
		 0 );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->old_repair_count,
		 value_32bit );
		libcnotify_printf(
		 "%s: old repair count\t\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->ecc_fix_success_count,
		 value_32bit );
		libcnotify_printf(
		 "%s: ECC fix success count\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );
		libesedb_debug_print_log_time(
		 ( (esedb_file_header_t *) file_header_data )->ecc_fix_success_time,
		 8,
		 "ECC fix success time",
		 "\t\t\t",
		 NULL );
		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->old_ecc_fix_success_count,
		 value_32bit );
		libcnotify_printf(
		 "%s: old ECC fix success count\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->ecc_fix_error_count,
		 value_32bit );
		libcnotify_printf(
		 "%s: ECC fix error count\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );
		libesedb_debug_print_log_time(
		 ( (esedb_file_header_t *) file_header_data )->ecc_fix_error_time,
		 8,
		 "ECC fix error time",
		 "\t\t\t",
		 NULL );
		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->old_ecc_fix_error_count,
		 value_32bit );
		libcnotify_printf(
		 "%s: old ECC fix error count\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->bad_checksum_error_count,
		 value_32bit );
		libcnotify_printf(
		 "%s: bad checksum error count\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );
		libesedb_debug_print_log_time(
		 ( (esedb_file_header_t *) file_header_data )->bad_checksum_error_time,
		 8,
		 "bad checksum error time",
		 "\t\t\t",
		 NULL );
		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->old_bad_checksum_error_count,
		 value_32bit );
		libcnotify_printf(
		 "%s: old bad checksum error count\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		libcnotify_printf(
		 "%s: committed log:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->committed_log,
		 4,
		 0 );

		libcnotify_printf(
		 "%s: previous shadow volume backup:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->previous_shadow_volume_backup,
		 24,
		 0 );
		libcnotify_printf(
		 "%s: previous differential backup:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->previous_differential_backup,
		 24,
		 0 );

		libcnotify_printf(
		 "%s: unknown4:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->unknown4,
		 40,
		 0 );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->nls_major_version,
		 value_32bit );
		libcnotify_printf(
		 "%s: NLS major version\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );
		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->nls_minor_version,
		 value_32bit );
		libcnotify_printf(
		 "%s: NLS minor version\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		libcnotify_printf(
		 "%s: unknown5:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_file_header_t *) file_header_data )->unknown5,
		 148,
		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_file_header_t *) file_header_data )->unknown_flags,
		 value_32bit );
		libcnotify_printf(
		 "%s: unknown flags\t\t\t: 0x%08" PRIx32 " (%" PRIu32 ")\n",
		 function,
		 value_32bit,
		 value_32bit );

		libcnotify_printf(
		 "\n" );
	}
#endif

	memory_free(
	 file_header_data );

	file_header_data = NULL;

	/* TODO add more values to internal structures */

	if( file_offset == 0 )
	{
		io_handle->format_version           = format_version;
		io_handle->format_revision          = format_revision;
		io_handle->page_size                = page_size;
		io_handle->creation_format_version  = creation_format_version;
		io_handle->creation_format_revision = creation_format_revision;
	}
	else
	{
		if( io_handle->format_version == 0 )
		{
			io_handle->format_version = format_version;
		}
		else if( io_handle->format_version != format_version )
		{
#if defined( HAVE_VERBOSE_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: mismatch in format version: 0x%" PRIx32 " and backup: 0x%" PRIx32 "\n",
				 function,
				 io_handle->format_version,
				 io_handle->format_version );
			}
#endif
		}
		if( io_handle->format_revision == 0 )
		{
			io_handle->format_revision = format_revision;
		}
		else if( io_handle->format_revision != format_revision )
		{
#if defined( HAVE_VERBOSE_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: mismatch in format revision: 0x%" PRIx32 " and backup: 0x%" PRIx32 "\n",
				 function,
				 io_handle->format_revision,
				 io_handle->format_revision );
			}
#endif
		}
		if( io_handle->page_size == 0 )
		{
			io_handle->page_size = page_size;
		}
		else if( io_handle->page_size != page_size )
		{
#if defined( HAVE_VERBOSE_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: mismatch in page size: 0x%04" PRIx32 " and backup: 0x%04" PRIx32 "\n",
				 function,
				 io_handle->page_size,
				 page_size );
			}
#endif
			/* The offset of the backup (database) file header
			 * is a good indication of the actual page size
			 */
			io_handle->page_size = (uint32_t) file_offset;
		}
	}
	return( 1 );

on_error:
	if( file_header_data != NULL )
	{
		memory_free(
		 file_header_data );
	}
	return( -1 );
}
/* Reads the users property view values
 * Returns 1 if successful, 0 if not supported or -1 on error
 */
int libfwsi_users_property_view_values_read_data(
     libfwsi_users_property_view_values_t *users_property_view_values,
     const uint8_t *data,
     size_t data_size,
     int ascii_codepage,
     libcerror_error_t **error )
{
	static char *function        = "libfwsi_users_property_view_values_read_data";
	size_t data_offset           = 0;
	uint32_t signature           = 0;
	uint16_t identifier_size     = 0;
	uint16_t item_data_size      = 0;
	uint16_t property_store_size = 0;

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

	if( users_property_view_values == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid users property view values.",
		 function );

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

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

		return( -1 );
	}
	/* Do not try to parse unsupported data sizes
	 */
	if( data_size < 14 )
	{
		return( 0 );
	}
	/* Do not try to parse unsupported shell item signatures
	 */
	byte_stream_copy_to_uint32_little_endian(
	 &( data[ 6 ] ),
	 signature );

	switch( signature )
	{
		case 0x10141981UL:
		case 0x23a3dfd5UL:
		case 0x23febbeeUL:
		case 0x3b93afbbUL:
		case 0xbeebee00UL:
			break;

		default:
			return( 0 );
	}
	byte_stream_copy_to_uint32_little_endian(
	 &( data[ 4 ] ),
	 item_data_size );

	byte_stream_copy_to_uint16_little_endian(
	 &( data[ 10 ] ),
	 property_store_size );

	byte_stream_copy_to_uint16_little_endian(
	 &( data[ 12 ] ),
	 identifier_size );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: class type indicator\t\t: 0x%02" PRIx8 "\n",
		 function,
		 data[ 2 ] );

		libcnotify_printf(
		 "%s: unknown1\t\t\t: 0x%02" PRIx8 "\n",
		 function,
		 data[ 3 ] );

		libcnotify_printf(
		 "%s: data size\t\t\t: %" PRIu16 "\n",
		 function,
		 item_data_size );

		libcnotify_printf(
		 "%s: data signature\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 signature );

		libcnotify_printf(
		 "%s: property store size\t\t: %" PRIu16 "\n",
		 function,
		 property_store_size );

		libcnotify_printf(
		 "%s: identifier size\t\t: %" PRIu16 "\n",
		 function,
		 identifier_size );
	}
#endif
	data_offset = 14;

	if( item_data_size != 0 )
	{
		if( item_data_size <= 2 )
		{
			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 );
		}
	}
/* TODO add identifier_size bounds check */
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: identifier data:\n",
		 function );
		libcnotify_print_data(
		 &( data[ data_offset ] ),
		 identifier_size,
		 0 );
	}
#endif
	switch( signature )
	{
		case 0x23a3dfd5UL:
		case 0x3b93afbbUL:
		case 0xbeebee00UL:
			if( identifier_size == 4 )
			{
#if defined( HAVE_DEBUG_OUTPUT )
				if( libcnotify_verbose != 0 )
				{
					byte_stream_copy_to_uint32_little_endian(
					 &( data[ data_offset ] ),
					 value_32bit );
					libcnotify_printf(
					 "%s: identifier\t\t\t: 0x%08" PRIx32 "\n",
					 function,
					 value_32bit );
				}
#endif
				data_offset += 4;
			}
			break;

		case 0x23febbeeUL:
			if( identifier_size == 16 )
			{
#if defined( HAVE_DEBUG_OUTPUT )
				if( libcnotify_verbose != 0 )
				{
					if( libfwsi_debug_print_guid_value(
					     function,
					     "known folder identifier\t",
					     &( data[ data_offset ] ),
					     16,
					     LIBFGUID_ENDIAN_LITTLE,
					     LIBFGUID_STRING_FORMAT_FLAG_USE_UPPER_CASE | LIBFGUID_STRING_FORMAT_FLAG_USE_SURROUNDING_BRACES,
					     error ) != 1 )
					{
						libcerror_error_set(
						 error,
						 LIBCERROR_ERROR_DOMAIN_RUNTIME,
						 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
						 "%s: unable to print GUID value.",
						 function );

						return( -1 );
					}
					libcnotify_printf(
					 "%s: known folder name\t\t: %s\n",
					 function,
					 libfwsi_known_folder_identifier_get_name(
					  &( data[ data_offset ] ) ) );
				}
#endif
				data_offset += 16;
			}
			break;

		default:
			data_offset += identifier_size;
			break;
	}
/* TODO add property store size bounds check */

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: property store data:\n",
		 function );
		libcnotify_print_data(
		 &( data[ data_offset ] ),
		 property_store_size,
		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
	}
#endif
	if( property_store_size > 0 )
	{
/* TODO look for multiple stores */
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			if( libfwsi_debug_print_property_storage_value(
			     &( data[ data_offset ] ),
			     property_store_size,
			     ascii_codepage,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
				 "%s: unable to print property storage value.",
				 function );

				return( -1 );
			}
		}
#endif
		data_offset += property_store_size;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		byte_stream_copy_to_uint16_little_endian(
		 &( data[ data_offset ] ),
		 value_16bit );

		libcnotify_printf(
		 "%s: unknown1 size\t\t\t: %" PRIu16 "\n",
		 function,
		 value_16bit );
	}
#endif
	data_offset += 2;

	if( signature == 0x23a3dfd5UL )
	{
		if( data_offset > data_size - 32 )
		{
			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 defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			if( libfwsi_debug_print_guid_value(
			     function,
			     "delegate item identifier\t",
			     &( data[ data_offset ] ),
			     16,
			     LIBFGUID_ENDIAN_LITTLE,
			     LIBFGUID_STRING_FORMAT_FLAG_USE_UPPER_CASE | LIBFGUID_STRING_FORMAT_FLAG_USE_SURROUNDING_BRACES,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
				 "%s: unable to print GUID value.",
				 function );

				return( -1 );
			}
		}
#endif
		data_offset += 16;

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			if( libfwsi_debug_print_guid_value(
			     function,
			     "item class identifier\t\t",
			     &( data[ data_offset ] ),
			     16,
			     LIBFGUID_ENDIAN_LITTLE,
			     LIBFGUID_STRING_FORMAT_FLAG_USE_UPPER_CASE | LIBFGUID_STRING_FORMAT_FLAG_USE_SURROUNDING_BRACES,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
				 "%s: unable to print GUID value.",
				 function );

				return( -1 );
			}
			libcnotify_printf(
			 "%s: shell folder name\t\t: %s\n",
			 function,
			 libfwsi_shell_folder_identifier_get_name(
			  &( data[ data_offset ] ) ) );
		}
#endif
		data_offset += 16;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "\n" );
	}
#endif
	return( 1 );
}
Exemple #18
0
/* Reads the version (resource) values
 * Returns 1 if successful or -1 on error
 */
int libwrc_version_values_read(
     libwrc_language_entry_t *language_entry,
     libwrc_io_handle_t *io_handle,
     libbfio_handle_t *file_io_handle,
     libwrc_data_descriptor_t *data_descriptor,
     libcerror_error_t **error )
{
	libwrc_version_values_t *version_values = NULL;
	libfvalue_value_t *value_identifier     = NULL;
	uint8_t *resource_data                  = NULL;
	uint8_t *version_resource_data          = NULL;
	static char *function                   = "libwrc_version_values_read";
	off64_t file_offset                     = 0;
	size_t alignment_padding_size           = 0;
	size_t resource_data_offset             = 0;
	size_t resource_data_size               = 0;
	ssize_t read_count                      = 0;
	uint32_t value_32bit                    = 0;
	uint16_t value_data_size                = 0;
	uint16_t value_data_type                = 0;
	uint16_t version_resource_data_size     = 0;
	int value_index                         = 0;

	if( language_entry == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid language entry.",
		 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 );
	}
	if( data_descriptor == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid data descriptor.",
		 function );

		return( -1 );
	}
	if( libwrc_version_values_initialize(
	     &version_values,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
		 "%s: unable to create version values.",
		 function );

		goto on_error;
	}
	file_offset = data_descriptor->virtual_address
	            - io_handle->virtual_address;

	if( libbfio_handle_seek_offset(
	     file_io_handle,
	     file_offset,
	     SEEK_SET,
	     error ) == -1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_SEEK_FAILED,
		 "%s: unable to seek resource data offset: %" PRIi64 ".",
		 function,
		 file_offset );

		goto on_error;
	}
	resource_data_size = (size_t) data_descriptor->size;

	resource_data = (uint8_t *) memory_allocate(
	                             sizeof( uint8_t ) * resource_data_size );

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

		goto on_error;
	}
	read_count = libbfio_handle_read_buffer(
	              file_io_handle,
	              resource_data,
	              resource_data_size,
	              error );

	if( read_count != (ssize_t) resource_data_size )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_READ_FAILED,
		 "%s: unable to read resource data.",
		 function );

		goto on_error;
	}
	version_resource_data = resource_data;

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: resource data:\n",
		 function );
		libcnotify_print_data(
		 version_resource_data,
		 resource_data_size,
		 0 );
	}
#endif
	byte_stream_copy_to_uint16_little_endian(
	 ( (wrc_version_value_header_t *) version_resource_data )->size,
	 version_resource_data_size );

	byte_stream_copy_to_uint16_little_endian(
	 ( (wrc_version_value_header_t *) version_resource_data )->value_data_size,
	 value_data_size );

	byte_stream_copy_to_uint16_little_endian(
	 ( (wrc_version_value_header_t *) version_resource_data )->value_data_type,
	 value_data_type );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: size\t\t\t\t\t: %" PRIu16 "\n",
		 function,
		 version_resource_data_size );

		libcnotify_printf(
		 "%s: value data size\t\t\t\t: %" PRIu16 "\n",
		 function,
		 value_data_size );

		libcnotify_printf(
		 "%s: value data type\t\t\t\t: %" PRIu16 "\n",
		 function,
		 value_data_type );

		libcnotify_printf(
		 "\n" );
	}
#endif
	resource_data_offset += sizeof( wrc_version_value_header_t );

	if( libfvalue_value_type_initialize(
	     &value_identifier,
	     LIBFVALUE_VALUE_TYPE_STRING_UTF16,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
		 "%s: unable to create value identifier value.",
		 function );

		goto on_error;
	}
	read_count = libfvalue_value_type_set_data_string(
	              value_identifier,
	              &( version_resource_data[ resource_data_offset ] ),
	              resource_data_size,
	              LIBFVALUE_CODEPAGE_UTF16_LITTLE_ENDIAN,
	              LIBFVALUE_VALUE_DATA_FLAG_MANAGED,
	              error );

	if( read_count == -1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
		 "%s: unable to set data of value identifier value.",
		 function );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: value identifier\t\t\t\t: ",
		 function );

		if( libfvalue_value_print(
		     value_identifier,
		     0,
		     0,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
			 "%s: unable to print value identifier value.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "\n" );
	}
#endif
	if( ( read_count != 32 )
	 || ( memory_compare(
	       &( version_resource_data[ resource_data_offset ] ),
	       libwrc_version_information_value_identifier,
	       32 ) != 0 ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported version resource value signature.",
		 function );

		goto on_error;
	}
	if( libfvalue_value_free(
	     &value_identifier,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
		 "%s: unable to free value identifier value.",
		 function );

		goto on_error;
	}
	resource_data_offset += read_count;

	if( ( resource_data_offset % 4 ) != 0 )
	{
		alignment_padding_size = 4 - ( resource_data_offset % 4 );

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: alignment padding:\n",
			 function );
			libcnotify_print_data(
			 &( version_resource_data[ resource_data_offset ] ),
			 alignment_padding_size,
			 0 );
		}
#endif
		resource_data_offset += alignment_padding_size;
	}
/* TODO refactor to separate function? */
	if( value_data_size > 0 )
	{
		if( value_data_size > resource_data_size )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: value data size value out of bounds.",
			 function );

			goto on_error;
		}
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: value data:\n",
			 function );
			libcnotify_print_data(
			 &( version_resource_data[ resource_data_offset ] ),
			 value_data_size,
			 0 );
		}
#endif
		byte_stream_copy_to_uint32_little_endian(
		 &( version_resource_data[ resource_data_offset + 8 ] ),
		 version_values->file_version );

		byte_stream_copy_to_uint32_little_endian(
		 &( version_resource_data[ resource_data_offset + 12 ] ),
		 value_32bit );

		version_values->file_version <<= 32;
		version_values->file_version  |= value_32bit;

		byte_stream_copy_to_uint32_little_endian(
		 &( version_resource_data[ resource_data_offset + 16 ] ),
		 version_values->product_version );

		byte_stream_copy_to_uint32_little_endian(
		 &( version_resource_data[ resource_data_offset + 20 ] ),
		 value_32bit );

		version_values->product_version <<= 32;
		version_values->product_version  |= value_32bit;

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			byte_stream_copy_to_uint32_little_endian(
			 &( version_resource_data[ resource_data_offset ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: signature\t\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			byte_stream_copy_to_uint32_little_endian(
			 &( version_resource_data[ resource_data_offset + 4 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: version\t\t\t\t\t: %" PRIu32 ".%" PRIu32 "\n",
			 function,
			 value_32bit >> 16,
			 value_32bit & 0x0000ffffUL );

			byte_stream_copy_to_uint32_little_endian(
			 &( version_resource_data[ resource_data_offset + 8 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: file version upper\t\t\t\t: %" PRIu32 ".%" PRIu32 "\n",
			 function,
			 value_32bit >> 16,
			 value_32bit & 0x0000ffffUL );

			byte_stream_copy_to_uint32_little_endian(
			 &( version_resource_data[ resource_data_offset + 12 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: file version lower\t\t\t\t: %" PRIu32 ".%" PRIu32 "\n",
			 function,
			 value_32bit >> 16,
			 value_32bit & 0x0000ffffUL );

			byte_stream_copy_to_uint32_little_endian(
			 &( version_resource_data[ resource_data_offset + 16 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: product version upper\t\t\t: %" PRIu32 ".%" PRIu32 "\n",
			 function,
			 value_32bit >> 16,
			 value_32bit & 0x0000ffffUL );

			byte_stream_copy_to_uint32_little_endian(
			 &( version_resource_data[ resource_data_offset + 20 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: product version lower\t\t\t: %" PRIu32 ".%" PRIu32 "\n",
			 function,
			 value_32bit >> 16,
			 value_32bit & 0x0000ffffUL );

			byte_stream_copy_to_uint32_little_endian(
			 &( version_resource_data[ resource_data_offset + 24 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: file flags bitmask\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			byte_stream_copy_to_uint32_little_endian(
			 &( version_resource_data[ resource_data_offset + 28 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: file flags\t\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			byte_stream_copy_to_uint32_little_endian(
			 &( version_resource_data[ resource_data_offset + 32 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: file operating system\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			byte_stream_copy_to_uint32_little_endian(
			 &( version_resource_data[ resource_data_offset + 36 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: file type\t\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			byte_stream_copy_to_uint32_little_endian(
			 &( version_resource_data[ resource_data_offset + 40 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: file sub type\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			byte_stream_copy_to_uint32_little_endian(
			 &( version_resource_data[ resource_data_offset + 44 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: file time upper\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			byte_stream_copy_to_uint32_little_endian(
			 &( version_resource_data[ resource_data_offset + 48 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: file time lower\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			libcnotify_printf(
			 "\n" );
		}
#endif
		resource_data_offset += value_data_size;
	}
/* Reads a physical volume label
 * Returns 1 if successful, 0 if not found or -1 on error
 */
int libvslvm_physical_volume_read_label(
     libvslvm_physical_volume_t *physical_volume,
     libbfio_pool_t *file_io_pool,
     int file_io_pool_entry,
     off64_t file_offset,
     libcerror_error_t **error )
{
	vslvm_data_area_descriptor_t data_area_descriptor_data;
	vslvm_physical_volume_label_header_t physical_volume_label_header;
	vslvm_physical_volume_header_t physical_volume_header;

	libvslvm_data_area_descriptor_t *data_area_descriptor         = NULL;
	libvslvm_internal_physical_volume_t *internal_physical_volume = NULL;
	static char *function                                         = "libvslvm_physical_volume_read_label";
	ssize_t read_count                                            = 0;
	uint64_t offset                                               = 0;
	uint64_t size                                                 = 0;
	int entry_index                                               = 0;
	int result                                                    = 0;

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

	if( physical_volume == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid physical volume.",
		 function );

		return( -1 );
	}
	internal_physical_volume = (libvslvm_internal_physical_volume_t *) physical_volume;

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: reading physical volume label at offset: %" PRIi64 "\n",
		 function,
		 file_offset );
	}
#endif
	if( libbfio_pool_seek_offset(
	     file_io_pool,
	     file_io_pool_entry,
	     file_offset,
	     SEEK_SET,
	     error ) == -1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_SEEK_FAILED,
		 "%s: unable to seek offset: %" PRIi64 " (0x%08" PRIx64 ").",
		 function,
		 file_offset,
		 file_offset );

		goto on_error;
	}
	read_count = libbfio_pool_read_buffer(
	              file_io_pool,
	              file_io_pool_entry,
	              (uint8_t *) &physical_volume_label_header,
	              sizeof( vslvm_physical_volume_label_header_t ),
	              error );

	if( read_count != (ssize_t) sizeof( vslvm_physical_volume_label_header_t ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_READ_FAILED,
		 "%s: unable to read physical volume label header.",
		 function );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: physical volume label header data:\n",
		 function );
		libcnotify_print_data(
		 (uint8_t *) &physical_volume_label_header,
		 sizeof( vslvm_physical_volume_label_header_t ),
		 0 );
	}
#endif
	if( memory_compare(
	     physical_volume_label_header.signature,
	     vslvm_physical_volume_label_signature,
	     8 ) != 0 )
	{
		return( 0 );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: signature\t\t\t\t: %c%c%c%c%c%c%c%c\n",
		 function,
		 physical_volume_label_header.signature[ 0 ],
		 physical_volume_label_header.signature[ 1 ],
		 physical_volume_label_header.signature[ 2 ],
		 physical_volume_label_header.signature[ 3 ],
		 physical_volume_label_header.signature[ 4 ],
		 physical_volume_label_header.signature[ 5 ],
		 physical_volume_label_header.signature[ 6 ],
		 physical_volume_label_header.signature[ 7 ] );

		byte_stream_copy_to_uint64_little_endian(
		 physical_volume_label_header.sector_number,
		 value_64bit );
		libcnotify_printf(
		 "%s: sector number\t\t\t: %" PRIu64 "\n",
		 function,
		 value_64bit );

		byte_stream_copy_to_uint32_little_endian(
		 physical_volume_label_header.checksum,
		 value_32bit );
		libcnotify_printf(
		 "%s: checksum\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 physical_volume_label_header.data_offset,
		 value_32bit );
		libcnotify_printf(
		 "%s: data offset\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		libcnotify_printf(
		 "%s: type indicator\t\t\t: %c%c%c%c%c%c%c%c\n",
		 function,
		 physical_volume_label_header.type_indicator[ 0 ],
		 physical_volume_label_header.type_indicator[ 1 ],
		 physical_volume_label_header.type_indicator[ 2 ],
		 physical_volume_label_header.type_indicator[ 3 ],
		 physical_volume_label_header.type_indicator[ 4 ],
		 physical_volume_label_header.type_indicator[ 5 ],
		 physical_volume_label_header.type_indicator[ 6 ],
		 physical_volume_label_header.type_indicator[ 7 ] );

		libcnotify_printf(
		 "\n" );
	}
#endif
/* TODO calculate checksum */

	read_count = libbfio_pool_read_buffer(
	              file_io_pool,
	              file_io_pool_entry,
	              (uint8_t *) &physical_volume_header,
	              sizeof( vslvm_physical_volume_header_t ),
	              error );

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

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: physical volume header data:\n",
		 function );
		libcnotify_print_data(
		 (uint8_t *) &physical_volume_header,
		 sizeof( vslvm_physical_volume_header_t ),
		 0 );
	}
#endif
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: identifier\t\t\t\t: %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",
		 function,
		 physical_volume_header.identifier[ 0 ],
		 physical_volume_header.identifier[ 1 ],
		 physical_volume_header.identifier[ 2 ],
		 physical_volume_header.identifier[ 3 ],
		 physical_volume_header.identifier[ 4 ],
		 physical_volume_header.identifier[ 5 ],
		 physical_volume_header.identifier[ 6 ],
		 physical_volume_header.identifier[ 7 ],
		 physical_volume_header.identifier[ 8 ],
		 physical_volume_header.identifier[ 9 ],
		 physical_volume_header.identifier[ 10 ],
		 physical_volume_header.identifier[ 11 ],
		 physical_volume_header.identifier[ 12 ],
		 physical_volume_header.identifier[ 13 ],
		 physical_volume_header.identifier[ 14 ],
		 physical_volume_header.identifier[ 15 ],
		 physical_volume_header.identifier[ 16 ],
		 physical_volume_header.identifier[ 17 ],
		 physical_volume_header.identifier[ 18 ],
		 physical_volume_header.identifier[ 19 ],
		 physical_volume_header.identifier[ 20 ],
		 physical_volume_header.identifier[ 21 ],
		 physical_volume_header.identifier[ 22 ],
		 physical_volume_header.identifier[ 23 ],
		 physical_volume_header.identifier[ 24 ],
		 physical_volume_header.identifier[ 25 ],
		 physical_volume_header.identifier[ 26 ],
		 physical_volume_header.identifier[ 27 ],
		 physical_volume_header.identifier[ 28 ],
		 physical_volume_header.identifier[ 29 ],
		 physical_volume_header.identifier[ 30 ],
		 physical_volume_header.identifier[ 31 ] );

		byte_stream_copy_to_uint64_little_endian(
		 physical_volume_header.volume_size,
		 value_64bit );
		libcnotify_printf(
		 "%s: volume size\t\t\t: %" PRIu64 "\n",
		 function,
		 value_64bit );

		libcnotify_printf(
		 "\n" );
	}
#endif
	do
	{
		read_count = libbfio_pool_read_buffer(
		              file_io_pool,
		              file_io_pool_entry,
		              (uint8_t *) &data_area_descriptor_data,
		              sizeof( vslvm_data_area_descriptor_t ),
		              error );

		if( read_count != (ssize_t) sizeof( vslvm_data_area_descriptor_t ) )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read data area descriptor.",
			 function );

			goto on_error;
		}
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: data area descriptor data:\n",
			 function );
			libcnotify_print_data(
			 (uint8_t *) &data_area_descriptor_data,
			 sizeof( vslvm_data_area_descriptor_t ),
			 0 );
		}
#endif
		result = memory_compare(
		          (uint8_t *) &data_area_descriptor_data,
		          vslvm_empty_data_area_descriptor,
		          sizeof( vslvm_data_area_descriptor_t ) );

		if( result != 0 )
		{
			byte_stream_copy_to_uint64_little_endian(
			 data_area_descriptor_data.offset,
			 offset );

			byte_stream_copy_to_uint64_little_endian(
			 data_area_descriptor_data.size,
			 size );

#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: data area offset\t\t\t: 0x%08" PRIx64 "\n",
				 function,
				 offset );

				libcnotify_printf(
				 "%s: data area size\t\t\t: %" PRIu64 "\n",
				 function,
				 size );

				libcnotify_printf(
				 "\n" );
			}
#endif
			if( libvslvm_data_area_descriptor_initialize(
			     &data_area_descriptor,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
				 "%s: unable to create data area descriptor.",
				 function );

				goto on_error;
			}
			if( libvslvm_data_area_descriptor_set(
			     data_area_descriptor,
			     (off64_t) offset,
			     (size64_t) size,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
				 "%s: unable to set data area descriptor.",
				 function );

				goto on_error;
			}
			if( libcdata_array_append_entry(
			     internal_physical_volume->data_area_descriptors_array,
			     &entry_index,
			     (intptr_t *) data_area_descriptor,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
				 "%s: unable to append entry to data area descriptors array.",
				 function );

				goto on_error;
			}
			data_area_descriptor = NULL;
		}
	}
	while( result != 0 );

	do
	{
		read_count = libbfio_pool_read_buffer(
		              file_io_pool,
		              file_io_pool_entry,
		              (uint8_t *) &data_area_descriptor_data,
		              sizeof( vslvm_data_area_descriptor_t ),
		              error );

		if( read_count != (ssize_t) sizeof( vslvm_data_area_descriptor_t ) )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read metadata area descriptor.",
			 function );

			goto on_error;
		}
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: metadata area descriptor data:\n",
			 function );
			libcnotify_print_data(
			 (uint8_t *) &data_area_descriptor_data,
			 sizeof( vslvm_data_area_descriptor_t ),
			 0 );
		}
#endif
		result = memory_compare(
		          (uint8_t *) &data_area_descriptor_data,
		          vslvm_empty_data_area_descriptor,
		          sizeof( vslvm_data_area_descriptor_t ) );

		if( result != 0 )
		{
			byte_stream_copy_to_uint64_little_endian(
			 data_area_descriptor_data.offset,
			 offset );

			byte_stream_copy_to_uint64_little_endian(
			 data_area_descriptor_data.size,
			 size );

#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: metadata area offset\t\t: 0x%08" PRIx64 "\n",
				 function,
				 offset );

				libcnotify_printf(
				 "%s: metadata area size\t\t\t: %" PRIu64 "\n",
				 function,
				 size );

				libcnotify_printf(
				 "\n" );
			}
#endif
			if( libvslvm_data_area_descriptor_initialize(
			     &data_area_descriptor,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
				 "%s: unable to create data area descriptor.",
				 function );

				goto on_error;
			}
			if( libvslvm_data_area_descriptor_set(
			     data_area_descriptor,
			     (off64_t) offset,
			     (size64_t) size,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
				 "%s: unable to set data area descriptor.",
				 function );

				goto on_error;
			}
			if( libcdata_array_append_entry(
			     internal_physical_volume->metadata_area_descriptors_array,
			     &entry_index,
			     (intptr_t *) data_area_descriptor,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
				 "%s: unable to append entry to metadata area descriptors array.",
				 function );

				goto on_error;
			}
			data_area_descriptor = NULL;
		}
	}
	while( result != 0 );

	return( 1 );

on_error:
	if( data_area_descriptor != NULL )
	{
		libvslvm_data_area_descriptor_free(
		 &data_area_descriptor,
		 NULL );
	}
	libcdata_array_empty(
	 internal_physical_volume->metadata_area_descriptors_array,
	 (int (*)(intptr_t **, libcerror_error_t **)) &libvslvm_data_area_descriptor_free,
	 NULL );

	libcdata_array_empty(
	 internal_physical_volume->data_area_descriptors_array,
	 (int (*)(intptr_t **, libcerror_error_t **)) &libvslvm_data_area_descriptor_free,
	 NULL );

	return( -1 );
}
Exemple #20
0
/* Retrieves the string index for a specific identifier
 * Returns 1 if successful, 0 if no such string identifier or -1 on error
 */
int libwrc_string_get_index_by_identifier(
     libwrc_resource_t *resource,
     uint32_t language_identifier,
     uint32_t string_identifier,
     int *string_index,
     libcerror_error_t **error )
{
	libfvalue_value_t *string_value               = NULL;
	libwrc_internal_resource_t *internal_resource = NULL;
	libwrc_language_entry_t *language_entry       = NULL;
	uint8_t *string_value_identifier              = NULL;
	static char *function                         = "libwrc_string_get_index_by_identifier";
	size_t string_value_identifier_size           = 0;
	uint32_t identifier                           = 0;
	int number_of_strings                         = 0;

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

		return( -1 );
	}
	internal_resource = (libwrc_internal_resource_t *) resource;

	if( internal_resource->resource_values == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: invalid resource - missing resource values.",
		 function );

		return( -1 );
	}
	if( internal_resource->resource_values->identifier != LIBWRC_RESOURCE_IDENTIFIER_STRING )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported resource type: 0x%08" PRIx32 ".",
		 function,
		 internal_resource->resource_values->identifier );

		return( -1 );
	}
	if( internal_resource->value == NULL )
	{
		if( libwrc_resource_read_value(
		     internal_resource,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read resource value.",
			 function );

			return( -1 );
		}
	}
	if( libwrc_language_table_get_entry_by_identifier(
	     (libwrc_language_table_t *) internal_resource->value,
	     language_identifier,
	     &language_entry,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve language entry for identifier: 0x%08" PRIx32 ".",
		 function,
		 language_identifier );

		return( -1 );
	}
	if( libwrc_language_entry_get_number_of_values(
	     language_entry,
	     &number_of_strings,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve number of strings.",
		 function );

		return( -1 );
	}
	for( *string_index = 0;
	     *string_index < number_of_strings;
	     *string_index += 1 )
	{
		if( libwrc_language_entry_get_value_by_index(
		     language_entry,
		     *string_index,
		     (intptr_t **) &string_value,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
			 "%s: unable to retrieve string value: %d.",
			 function,
			 string_index );

			return( -1 );
		}
		if( libfvalue_value_get_identifier(
		     string_value,
		     &string_value_identifier,
		     &string_value_identifier_size,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
			 "%s: unable to retrieve string value: %d identifier.",
			 function,
			 string_index );

			return( -1 );
		}
		if( string_value_identifier == NULL )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
			 "%s: missing string value identifier.",
			 function );

			return( -1 );
		}
		if( string_value_identifier_size != 4 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: string size value out of bound.",
			 function );

			return( -1 );
		}
		byte_stream_copy_to_uint32_little_endian(
		 string_value_identifier,
		 identifier );

		if( identifier == string_identifier )
		{
			return( 1 );
		}
	}
	return( 0 );
}
/* Reads the store block
 * Returns 1 if successful or -1 on error
 */
int libvshadow_store_block_read(
     libvshadow_store_block_t *store_block,
     libbfio_handle_t *file_io_handle,
     off64_t file_offset,
     libcerror_error_t **error )
{
	static char *function       = "libvshadow_store_block_read";
	ssize_t read_count          = 0;

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

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

	if( store_block == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid store block.",
		 function );

		return( -1 );
	}
	if( store_block->data == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
		 "%s: invalid store block - missing data.",
		 function );

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

		return( -1 );
	}
	read_count = libbfio_handle_read_buffer(
	              file_io_handle,
	              store_block->data,
	              store_block->data_size,
	              error );

	if( read_count != (ssize_t) store_block->data_size )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_READ_FAILED,
		 "%s: unable to read block data.",
		 function );

		return( -1 );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: store block header:\n",
		 function );
		libcnotify_print_data(
		 store_block->data,
		 sizeof( vshadow_store_block_header_t ),
		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
	}
#endif
	if( memory_compare(
	     ( (vshadow_store_block_header_t *) store_block->data )->identifier,
	     vshadow_vss_identifier,
	     8 ) != 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: invalid store block list header identifier.",
		 function );

		return( -1 );
	}
	byte_stream_copy_to_uint32_little_endian(
	 ( (vshadow_store_block_header_t *) store_block->data )->version,
	 store_block->version );

	byte_stream_copy_to_uint32_little_endian(
	 ( (vshadow_store_block_header_t *) store_block->data )->record_type,
	 store_block->record_type );

	byte_stream_copy_to_uint64_little_endian(
	 ( (vshadow_store_block_header_t *) store_block->data )->relative_offset,
	 store_block->relative_offset );

	byte_stream_copy_to_uint64_little_endian(
	 ( (vshadow_store_block_header_t *) store_block->data )->offset,
	 store_block->offset );

	byte_stream_copy_to_uint64_little_endian(
	 ( (vshadow_store_block_header_t *) store_block->data )->next_offset,
	 store_block->next_offset );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		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 );

			return( -1 );
		}
		if( libfguid_identifier_copy_from_byte_stream(
		     guid,
		     ( (vshadow_store_block_header_t *) store_block->data )->identifier,
		     16,
		     LIBFGUID_ENDIAN_LITTLE,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
			 "%s: unable to copy byte stream to GUID.",
			 function );

			return( -1 );
		}
#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 );

			return( -1 );
		}
		libcnotify_printf(
		 "%s: identifier\t\t\t\t\t: %" PRIs_LIBCSTRING_SYSTEM "\n",
		 function,
		 guid_string );

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

		libcnotify_printf(
		 "%s: record type\t\t\t\t: %" PRIu32 "\n",
		 function,
		 store_block->record_type );

		libcnotify_printf(
		 "%s: relative offset\t\t\t\t: 0x%08" PRIx64 "\n",
		 function,
		 store_block->relative_offset );

		libcnotify_printf(
		 "%s: offset\t\t\t\t\t: 0x%08" PRIx64 "\n",
		 function,
		 store_block->offset );

		libcnotify_printf(
		 "%s: next offset\t\t\t\t: 0x%08" PRIx64 "\n",
		 function,
		 store_block->next_offset );

		byte_stream_copy_to_uint64_little_endian(
		 ( (vshadow_store_block_header_t *) store_block->data )->unknown1,
		 value_64bit );
		libcnotify_printf(
		 "%s: unknown1\t\t\t\t\t: %" PRIu64 "\n",
		 function,
		 value_64bit );

		libcnotify_printf(
		 "%s: unknown2:\n",
		 function );
		libcnotify_print_data(
		 ( (vshadow_store_block_header_t *) store_block->data )->unknown2,
		 72,
		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );

		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 );

			return( -1 );
		}
	}
#endif
	if( store_block->version != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported version: %" PRIu32 ".",
		 function,
		 store_block->version );

		return( -1 );
	}
	return( 1 );
}
Exemple #22
0
/* Reads the unencrypted volume header
 * Returns 1 if successful or -1 on error
 */
int libbde_io_handle_read_unencrypted_volume_header(
     libbde_io_handle_t *io_handle,
     libbfio_handle_t *file_io_handle,
     libcerror_error_t **error )
{
	libbde_sector_data_t *sector_data = NULL;
	uint8_t *volume_header_data       = NULL;
	static char *function             = "libbde_io_handle_read_unencrypted_volume_header";
	off64_t volume_header_offset      = 0;
	uint64_t total_number_of_sectors  = 0;

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

		goto on_error;
	}
	if( ( io_handle->version == LIBBDE_VERSION_WINDOWS_7 )
	 || ( io_handle->version == LIBBDE_VERSION_TO_GO ) )
	{
		volume_header_offset = io_handle->volume_header_offset;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: reading unencrypted volume header at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
		 function,
		 volume_header_offset,
		 volume_header_offset );
	}
#endif
	if( libbde_sector_data_initialize(
	     &sector_data,
	     io_handle->bytes_per_sector,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
		 "%s: unable to create sector data.",
		 function );

		goto on_error;
	}
	if( libbde_sector_data_read(
	     sector_data,
	     io_handle,
	     file_io_handle,
	     volume_header_offset,
	     io_handle->encryption_context,
	     0,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_IO,
		 LIBCERROR_IO_ERROR_READ_FAILED,
		 "%s: unable to read volume header sector data.",
		 function );

		goto on_error;
	}
	volume_header_data = sector_data->data;

	if( io_handle->volume_size == 0 )
	{
		if( memory_compare(
		     &( volume_header_data[ 3 ] ),
		     bde_ntfs_volume_file_system_signature,
		     8 ) == 0 )
		{
			byte_stream_copy_to_uint16_little_endian(
			 ( (bde_volume_header_windows_vista_t *) volume_header_data )->total_number_of_sectors_16bit,
			 total_number_of_sectors );

			if( total_number_of_sectors == 0 )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (bde_volume_header_windows_vista_t *) volume_header_data )->total_number_of_sectors_32bit,
				 total_number_of_sectors );
			}
			if( total_number_of_sectors == 0 )
			{
				byte_stream_copy_to_uint64_little_endian(
				 ( (bde_volume_header_windows_vista_t *) volume_header_data )->total_number_of_sectors_64bit,
				 total_number_of_sectors );
			}
			if( total_number_of_sectors == 0 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_MISSING,
				 "%s: missing total number of sectors.",
				 function );

				goto on_error;
			}
			io_handle->volume_size  = total_number_of_sectors;
			io_handle->volume_size *= io_handle->bytes_per_sector;
		}
		else
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
			 "%s: unable to determine volume size.",
			 function );

			goto on_error;
		}
	}
	if( libbde_sector_data_free(
	     &sector_data,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
		 "%s: unable to free sector data.",
		 function );

		goto on_error;
	}
	sector_data = NULL;

	return( 1 );

on_error:
	if( sector_data != NULL )
	{
		libbde_sector_data_free(
		 &sector_data,
		 NULL );
	}
	return( -1 );
}
/* Reads the file information
 * Returns 1 if successful or -1 on error
 */
int libscca_file_information_read_data(
     libscca_file_information_t *file_information,
     libscca_io_handle_t *io_handle,
     const uint8_t *data,
     size_t data_size,
     libcerror_error_t **error )
{
	static char *function             = "libscca_file_information_read_data";
	size_t file_information_data_size = 0;
	int last_run_time_index           = 0;
	int number_of_last_run_times      = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	uint64_t value_64bit              = 0;
	uint32_t value_32bit              = 0;
	int result                        = 0;
#endif

	if( file_information == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid file information.",
		 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 );
	}
	if( ( io_handle->format_version != 17 )
	 && ( io_handle->format_version != 23 )
	 && ( io_handle->format_version != 26 )
	 && ( io_handle->format_version != 30 ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
		 "%s: invalid IO handle - unsupported format version.",
		 function );

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

		return( -1 );
	}
	if( data_size < file_information_data_size )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
		 "%s: invalid data size value too small.",
		 function );

		return( -1 );
	}
	if( data_size > (size_t) SSIZE_MAX )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
		 "%s: invalid data size value exceeds maximum.",
		 function );

		return( -1 );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: file information data:\n",
		 function );
		libcnotify_print_data(
		 data,
		 file_information_data_size,
		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
	}
#endif
	byte_stream_copy_to_uint32_little_endian(
	 ( (scca_file_information_v17_t *) data )->metrics_array_offset,
	 file_information->metrics_array_offset );

	byte_stream_copy_to_uint32_little_endian(
	 ( (scca_file_information_v17_t *) data )->number_of_file_metrics_entries,
	 file_information->number_of_file_metrics_entries );

	byte_stream_copy_to_uint32_little_endian(
	 ( (scca_file_information_v17_t *) data )->trace_chain_array_offset,
	 file_information->trace_chain_array_offset );

	byte_stream_copy_to_uint32_little_endian(
	 ( (scca_file_information_v17_t *) data )->number_of_trace_chain_array_entries,
	 file_information->number_of_trace_chain_array_entries );

	byte_stream_copy_to_uint32_little_endian(
	 ( (scca_file_information_v17_t *) data )->filename_strings_offset,
	 file_information->filename_strings_offset );

	byte_stream_copy_to_uint32_little_endian(
	 ( (scca_file_information_v17_t *) data )->filename_strings_size,
	 file_information->filename_strings_size );

	byte_stream_copy_to_uint32_little_endian(
	 ( (scca_file_information_v17_t *) data )->volumes_information_offset,
	 file_information->volumes_information_offset );

	byte_stream_copy_to_uint32_little_endian(
	 ( (scca_file_information_v17_t *) data )->number_of_volumes,
	 file_information->number_of_volumes );

	byte_stream_copy_to_uint32_little_endian(
	 ( (scca_file_information_v17_t *) data )->volumes_information_size,
	 file_information->volumes_information_size );

	if( io_handle->format_version < 26 )
	{
		number_of_last_run_times = 1;
	}
	else
	{
		number_of_last_run_times = 8;
	}
	for( last_run_time_index = 0;
	     last_run_time_index < number_of_last_run_times;
	     last_run_time_index++ )
	{
		if( io_handle->format_version == 17 )
		{
			byte_stream_copy_to_uint64_little_endian(
			 &( ( (scca_file_information_v17_t *) data )->last_run_time[ last_run_time_index * 8 ] ),
			 file_information->last_run_time[ last_run_time_index ] );
		}
		else if( io_handle->format_version == 23 )
		{
			byte_stream_copy_to_uint64_little_endian(
			 &( ( (scca_file_information_v23_t *) data )->last_run_time[ last_run_time_index * 8 ] ),
			 file_information->last_run_time[ last_run_time_index ] );
		}
		else if( ( io_handle->format_version == 26 )
		      || ( io_handle->format_version == 30 ) )
		{
			byte_stream_copy_to_uint64_little_endian(
			 &( ( (scca_file_information_v26_t *) data )->last_run_time[ last_run_time_index * 8 ] ),
			 file_information->last_run_time[ last_run_time_index ] );
		}
	}
	if( io_handle->format_version == 17 )
	{
		byte_stream_copy_to_uint32_little_endian(
		 ( (scca_file_information_v17_t *) data )->run_count,
		 file_information->run_count );
	}
	else if( io_handle->format_version == 23 )
	{
		byte_stream_copy_to_uint32_little_endian(
		 ( (scca_file_information_v23_t *) data )->run_count,
		 file_information->run_count );
	}
	else if( ( io_handle->format_version == 26 )
	      || ( io_handle->format_version == 30 ) )
	{
		byte_stream_copy_to_uint32_little_endian(
		 ( (scca_file_information_v26_t *) data )->run_count,
		 file_information->run_count );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: metrics array offset\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 file_information->metrics_array_offset );

		libcnotify_printf(
		 "%s: number of file metrics entries\t\t: %" PRIu32 "\n",
		 function,
		 file_information->number_of_file_metrics_entries );

		libcnotify_printf(
		 "%s: trace chain array offset\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 file_information->trace_chain_array_offset );

		libcnotify_printf(
		 "%s: number of trace chain array entries\t\t: %" PRIu32 "\n",
		 function,
		 file_information->number_of_trace_chain_array_entries );

		libcnotify_printf(
		 "%s: filename strings offset\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 file_information->filename_strings_offset );

		libcnotify_printf(
		 "%s: filename strings size\t\t\t: %" PRIu32 "\n",
		 function,
		 file_information->filename_strings_size );

		libcnotify_printf(
		 "%s: volumes information offset\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 file_information->volumes_information_offset );

		libcnotify_printf(
		 "%s: number of volumes\t\t\t\t: %" PRIu32 "\n",
		 function,
		 file_information->number_of_volumes );

		libcnotify_printf(
		 "%s: volumes information size\t\t\t: %" PRIu32 "\n",
		 function,
		 file_information->volumes_information_size );

		if( io_handle->format_version == 23 )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (scca_file_information_v23_t *) data )->unknown3c,
			 value_32bit );
			libcnotify_printf(
			 "%s: unknown3c\t\t\t\t: 0x%08" PRIx64 "\n",
			 function,
			 value_64bit );
		}
		for( last_run_time_index = 0;
		     last_run_time_index < number_of_last_run_times;
		     last_run_time_index++ )
		{
			if( io_handle->format_version == 17 )
			{
				result = libscca_debug_print_filetime_value(
					  function,
					  "last run time:\t\t\t\t",
				          &( ( (scca_file_information_v17_t *) data )->last_run_time[ last_run_time_index * 8 ] ),
					  8,
					  LIBFDATETIME_ENDIAN_LITTLE,
				          LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
					  error );
			}
			else if( io_handle->format_version == 23 )
			{
				result = libscca_debug_print_filetime_value(
					  function,
					  "last run time:\t\t\t\t",
				          &( ( (scca_file_information_v23_t *) data )->last_run_time[ last_run_time_index * 8 ] ),
					  8,
					  LIBFDATETIME_ENDIAN_LITTLE,
				          LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
					  error );
			}
			else if( ( io_handle->format_version == 26 )
			      || ( io_handle->format_version == 30 ) )
			{
				result = libscca_debug_print_filetime_value(
					  function,
					  "last run time:\t\t\t\t",
				          &( ( (scca_file_information_v26_t *) data )->last_run_time[ last_run_time_index * 8 ] ),
					  8,
					  LIBFDATETIME_ENDIAN_LITTLE,
				          LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME_NANO_SECONDS,
					  error );
			}
			if( result != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
				 "%s: unable to print filetime value.",
				 function );

				return( -1 );
			}
		}
		libcnotify_printf(
		 "%s: unknown4:\n",
		 function );

		if( io_handle->format_version == 17 )
		{
			libcnotify_print_data(
			 ( (scca_file_information_v17_t *) data )->unknown4,
			 16,
			 0 );
		}
		else if( io_handle->format_version == 23 )
		{
			libcnotify_print_data(
			 ( (scca_file_information_v23_t *) data )->unknown4,
			 16,
			 0 );
		}
		else if( ( io_handle->format_version == 26 )
		      || ( io_handle->format_version == 30 ) )
		{
			libcnotify_print_data(
			 ( (scca_file_information_v26_t *) data )->unknown4,
			 16,
			 0 );
		}
		libcnotify_printf(
		 "%s: run count\t\t\t\t: %" PRIu32 "\n",
		 function,
		 file_information->run_count );

		if( io_handle->format_version == 17 )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (scca_file_information_v17_t *) data )->unknown5,
			 value_32bit );
			libcnotify_printf(
			 "%s: unknown5\t\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			libcnotify_printf(
			 "\n" );
		}
		else if( io_handle->format_version == 23 )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (scca_file_information_v23_t *) data )->unknown5,
			 value_32bit );
			libcnotify_printf(
			 "%s: unknown5\t\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			libcnotify_printf(
			 "%s: unknown6:\n",
			 function );
			libcnotify_print_data(
			 ( (scca_file_information_v23_t *) data )->unknown6,
			 80,
			 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
		}
		else if( ( io_handle->format_version == 26 )
		      || ( io_handle->format_version == 30 ) )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (scca_file_information_v26_t *) data )->unknown5a,
			 value_32bit );
			libcnotify_printf(
			 "%s: unknown5a\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			byte_stream_copy_to_uint32_little_endian(
			 ( (scca_file_information_v26_t *) data )->unknown5b,
			 value_32bit );
			libcnotify_printf(
			 "%s: unknown5b\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			libcnotify_printf(
			 "%s: unknown6:\n",
			 function );
			libcnotify_print_data(
			 ( (scca_file_information_v26_t *) data )->unknown6,
			 88,
			 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
		}
	}
#endif
	return( 1 );
}
Exemple #24
0
/* Reads the file header
 * Returns 1 if successful or -1 on error
 */
int libevt_io_handle_read_file_header(
     libevt_io_handle_t *io_handle,
     libbfio_handle_t *file_io_handle,
     uint32_t *first_record_offset,
     uint32_t *end_of_file_record_offset,
     libcerror_error_t **error )
{
	evt_file_header_t file_header;

	static char *function = "libevt_io_handle_read_file_header";
	ssize_t read_count    = 0;
	uint32_t size         = 0;
	uint32_t size_copy    = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	uint32_t value_32bit  = 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( first_record_offset == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid first record offset.",
		 function );

		return( -1 );
	}
	if( end_of_file_record_offset == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid end of file record offset.",
		 function );

		return( -1 );
	}
	if( libbfio_handle_get_size(
	     file_io_handle,
	     &( io_handle->file_size ),
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve file size.",
		 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 );

		return( -1 );
	}
	read_count = libbfio_handle_read_buffer(
	              file_io_handle,
	              (uint8_t *) &file_header,
	              sizeof( evt_file_header_t ),
	              error );

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

		return( -1 );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: file header:\n",
		 function );
		libcnotify_print_data(
		 (uint8_t *) &file_header,
		 sizeof( evt_file_header_t ),
		 0 );
	}
#endif
	if( memory_compare(
	     file_header.signature,
	     evt_file_signature,
	     4 ) != 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported file signature.",
		 function );

		return( -1 );
	}
	byte_stream_copy_to_uint32_little_endian(
	 file_header.size,
	 size );

	byte_stream_copy_to_uint32_little_endian(
	 file_header.major_version,
	 io_handle->major_version );

	byte_stream_copy_to_uint32_little_endian(
	 file_header.minor_version,
	 io_handle->minor_version );

	byte_stream_copy_to_uint32_little_endian(
	 file_header.first_record_offset,
	 *first_record_offset );

	byte_stream_copy_to_uint32_little_endian(
	 file_header.end_of_file_record_offset,
	 *end_of_file_record_offset );

	byte_stream_copy_to_uint32_little_endian(
	 file_header.file_flags,
	 io_handle->file_flags );

	byte_stream_copy_to_uint32_little_endian(
	 file_header.size_copy,
	 size_copy );

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

		libcnotify_printf(
		 "%s: signature\t\t\t\t: %c%c%c%c\n",
		 function,
		 file_header.signature[ 0 ],
		 file_header.signature[ 1 ],
		 file_header.signature[ 2 ],
		 file_header.signature[ 3 ] );

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

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

		libcnotify_printf(
		 "%s: first record offset\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 *first_record_offset );

		libcnotify_printf(
		 "%s: end of file record offset\t\t: 0x%08" PRIx32 "\n",
		 function,
		 *end_of_file_record_offset );

		byte_stream_copy_to_uint32_little_endian(
		 file_header.last_record_number,
		 value_32bit );
		libcnotify_printf(
		 "%s: last record number\t\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 file_header.first_record_number,
		 value_32bit );
		libcnotify_printf(
		 "%s: first record number\t\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		libcnotify_printf(
		 "%s: file flags\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 io_handle->file_flags );
		libevt_debug_print_file_flags(
		 io_handle->file_flags );
		libcnotify_printf(
		 "\n" );

		byte_stream_copy_to_uint32_little_endian(
		 file_header.retention,
		 value_32bit );
		libcnotify_printf(
		 "%s: retention\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		libcnotify_printf(
		 "%s: size copy\t\t\t\t: %" PRIu32 "\n",
		 function,
		 size_copy );

		libcnotify_printf(
		 "\n" );
	}
#endif
	if( size != size_copy )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: value mismatch for size and copy ( %" PRIu32 " != %" PRIu32 " ).\n",
			 function,
			 size,
			 size_copy );
		}
#endif
		/* If the size does not match the header size assume size copy contains
		 * the correct value for the next validation check
		 */
		if( size != sizeof( evt_file_header_t ) )
		{
			size = size_copy;
		}
		io_handle->flags |= LIBEVT_IO_HANDLE_FLAG_IS_CORRUPTED;
	}
	if( (size_t) size != sizeof( evt_file_header_t ) )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: size: %" PRIu32 " does not match header size.\n",
			 function,
			 size );
		}
#endif
		io_handle->flags |= LIBEVT_IO_HANDLE_FLAG_IS_CORRUPTED;
	}
	return( 1 );
}
/* Reads the channel
 * Returns 1 if successful or -1 on error
 */
int libfwevt_channel_read(
     libfwevt_channel_t *channel,
     const uint8_t *data,
     size_t data_size,
     size_t data_offset,
     libcerror_error_t **error )
{
	libfwevt_internal_channel_t *internal_channel = NULL;
	fwevt_template_channel_t *wevt_channel        = NULL;
	static char *function                         = "libfwevt_channel_read";
	uint32_t channel_data_offset                  = 0;
	uint32_t channel_data_size                    = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	libcstring_system_character_t *value_string   = NULL;
	size_t value_string_size                      = 0;
	uint32_t value_32bit                          = 0;
	int result                                    = 0;
#endif

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

		return( -1 );
	}
	internal_channel = (libfwevt_internal_channel_t *) channel;

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

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

		return( -1 );
	}
	if( data_offset >= data_size )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
		 "%s: invalid data offset value out of bounds.",
		 function );

		return( -1 );
	}
	if( ( data_size < sizeof( fwevt_template_channel_t ) )
	 || ( data_offset > ( data_size - sizeof( fwevt_template_channel_t ) ) ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
		 "%s: invalid data value too small.",
		 function );

		return( -1 );
	}
	wevt_channel = (fwevt_template_channel_t *) &( data[ data_offset ] );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: channel data:\n",
		 function );
		libcnotify_print_data(
		 (uint8_t *) wevt_channel,
		 sizeof( fwevt_template_channel_t ),
		 0 );
	}
#endif
	byte_stream_copy_to_uint32_little_endian(
	 wevt_channel->identifier,
	 internal_channel->identifier );

	byte_stream_copy_to_uint32_little_endian(
	 wevt_channel->data_offset,
	 channel_data_offset );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: identifier\t\t\t\t\t: %" PRIu32 "\n",
		 function,
		 internal_channel->identifier );

		libcnotify_printf(
		 "%s: data offset\t\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 channel_data_offset );

		byte_stream_copy_to_uint32_little_endian(
		 wevt_channel->unknown1,
		 value_32bit );
		libcnotify_printf(
		 "%s: unknown1\t\t\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 wevt_channel->message_identifier,
		 value_32bit );
		libcnotify_printf(
		 "%s: message identifier\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );
	}
#endif
	if( channel_data_offset > 0 )
	{
		if( channel_data_offset >= data_size )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: invalid channel data offset value out of bounds.",
			 function );

			goto on_error;
		}
		if( ( channel_data_size > data_size )
		 || ( ( channel_data_offset + channel_data_size ) > data_size ) )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: invalid channel data size value out of bounds.",
			 function );

			goto on_error;
		}
		byte_stream_copy_to_uint32_little_endian(
		 &( data[ channel_data_offset ] ),
		 channel_data_size );

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: data:\n",
			 function );
			libcnotify_print_data(
			 &( data[ channel_data_offset ] ),
			 channel_data_size,
			 0 );
		}
#endif
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: data size\t\t\t\t\t: %" PRIu32 "\n",
			 function,
			 channel_data_size );
		}
		channel_data_offset += 4;
		channel_data_size   -= 4;
#endif

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
			result = libuna_utf16_string_size_from_utf16_stream(
				  &( data[ channel_data_offset ] ),
				  channel_data_size,
				  LIBUNA_ENDIAN_LITTLE,
				  &value_string_size,
				  error );
#else
			result = libuna_utf8_string_size_from_utf16_stream(
				  &( data[ channel_data_offset ] ),
				  channel_data_size,
				  LIBUNA_ENDIAN_LITTLE,
				  &value_string_size,
				  error );
#endif
			if( result != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
				 "%s: unable to determine size of data string.",
				 function );

				goto on_error;
			}
			if( ( value_string_size > (size_t) SSIZE_MAX )
			 || ( ( sizeof( libcstring_system_character_t ) * value_string_size ) > (size_t) SSIZE_MAX ) )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
				 "%s: invalid data string size value exceeds maximum.",
				 function );

				goto on_error;
			}
			value_string = libcstring_system_string_allocate(
			                value_string_size );

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

				goto on_error;
			}
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
			result = libuna_utf16_string_copy_from_utf16_stream(
				  (libuna_utf16_character_t *) value_string,
				  value_string_size,
				  &( data[ channel_data_offset ] ),
				  channel_data_size,
				  LIBUNA_ENDIAN_LITTLE,
				  error );
#else
			result = libuna_utf8_string_copy_from_utf16_stream(
				  (libuna_utf8_character_t *) value_string,
				  value_string_size,
				  &( data[ channel_data_offset ] ),
				  channel_data_size,
				  LIBUNA_ENDIAN_LITTLE,
				  error );
#endif
			if( result != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
				 "%s: unable to set data string.",
				 function );

				goto on_error;
			}
			libcnotify_printf(
			 "%s: name\t\t\t\t\t\t: %" PRIs_LIBCSTRING_SYSTEM "\n",
			 function,
			 value_string );

			memory_free(
			 value_string );

			value_string = NULL;
		}
#endif
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "\n" );
	}
#endif
	return( 1 );

on_error:
#if defined( HAVE_DEBUG_OUTPUT )
	if( value_string != NULL )
	{
		memory_free(
		 value_string );
	}
#endif
	return( -1 );
}
/* Reads the control panel category values
 * Returns 1 if successful, 0 if not supported or -1 on error
 */
int libfwsi_control_panel_category_values_read_data(
     libfwsi_control_panel_category_values_t *control_panel_category_values,
     const uint8_t *data,
     size_t data_size,
     libcerror_error_t **error )
{
	static char *function = "libfwsi_control_panel_category_values_read_data";
        uint32_t signature    = 0;

#if defined( HAVE_DEBUG_OUTPUT )
        uint32_t value_32bit  = 0;
#endif

	if( control_panel_category_values == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid control panel category values.",
		 function );

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

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

		return( -1 );
	}
	/* Do not try to parse unsupported data sizes
	 */
	if( data_size < 12 )
	{
		return( 0 );
	}
	/* Do not try to parse unsupported shell item signatures
	 */
	byte_stream_copy_to_uint32_little_endian(
	 &( data[ 4 ] ),
	 signature );

	if( signature != 0x39de2184UL )
	{
		return( 0 );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: class type indicator\t: 0x%02" PRIx8 "\n",
		 function,
		 data[ 2 ] );

		libcnotify_printf(
		 "%s: unknown1\t\t\t: 0x%02" PRIx8 "\n",
		 function,
		 data[ 3 ] );

		libcnotify_printf(
		 "%s: signature\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 signature );

		byte_stream_copy_to_uint32_little_endian(
		 &( data[ 8 ] ),
		 value_32bit );
		libcnotify_printf(
		 "%s: control panel category\t: %" PRIu32 " (%s)\n",
		 function,
		 value_32bit,
		 libfwsi_debug_print_control_panel_category(
		  value_32bit ) );

		libcnotify_printf(
		 "\n" );
	}
#endif
	return( 1 );
}
/* Reads the delegate values
 * Returns 1 if successful, 0 if not supported or -1 on error
 */
int libfwsi_delegate_values_read_data(
     libfwsi_delegate_values_t *delegate_values,
     const uint8_t *data,
     size_t data_size,
     libcerror_error_t **error )
{
	static char *function   = "libfwsi_delegate_values_read_data";
	size_t data_offset      = 0;
	uint16_t item_data_size = 0;

	if( delegate_values == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid delegate values.",
		 function );

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

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

		return( -1 );
	}
	/* Do not try to parse unsupported data sizes
	 */
	if( data_size < 38 )
	{
		return( 0 );
	}
	/* Do not try to parse unknown class type indicators
	 */
	if( memory_compare(
	     &( data[ data_size - 32 ] ),
	     libfwsi_delegate_item_identifier,
	     16 ) != 0 )
	{
		return( 0 );
	}
	byte_stream_copy_to_uint32_little_endian(
	 &( data[ 4 ] ),
	 item_data_size );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: class type indicator\t\t\t: 0x%02" PRIx8 "\n",
		 function,
		 data[ 2 ] );

		libcnotify_printf(
		 "%s: unknown1\t\t\t\t: 0x%02" PRIx8 "\n",
		 function,
		 data[ 3 ] );

		libcnotify_printf(
		 "%s: delegate item data size\t\t: %" PRIu16 "\n",
		 function,
		 item_data_size );
	}
#endif
	data_offset = 6;

	if( item_data_size > 0 )
	{
		if( item_data_size > ( data_size - 32 ) )
		{
			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 defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: delegate item data:\n",
			 function );
			libcnotify_print_data(
			 &( data[ 6 ] ),
			 item_data_size,
			 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
		}
#endif
		data_offset += item_data_size;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		if( libfwsi_debug_print_guid_value(
		     function,
		     "delegate item class identifier\t",
		     &( data[ data_offset ] ),
		     16,
		     LIBFGUID_ENDIAN_LITTLE,
		     LIBFGUID_STRING_FORMAT_FLAG_USE_UPPER_CASE | LIBFGUID_STRING_FORMAT_FLAG_USE_SURROUNDING_BRACES,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
			 "%s: unable to print GUID value.",
			 function );

			return( -1 );
		}
	}
#endif
	data_offset += 16;

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		if( libfwsi_debug_print_guid_value(
		     function,
		     "item class identifier\t\t",
		     &( data[ data_offset ] ),
		     16,
		     LIBFGUID_ENDIAN_LITTLE,
		     LIBFGUID_STRING_FORMAT_FLAG_USE_UPPER_CASE | LIBFGUID_STRING_FORMAT_FLAG_USE_SURROUNDING_BRACES,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_PRINT_FAILED,
			 "%s: unable to print GUID value.",
			 function );

			return( -1 );
		}
		libcnotify_printf(
		 "%s: shell folder name\t\t\t: %s\n",
		 function,
		 libfwsi_shell_folder_identifier_get_name(
		  &( data[ data_offset ] ) ) );

		libcnotify_printf(
		 "\n" );
	}
#endif
	data_offset += 16;

	return( 1 );
}