/* 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 );
}
Exemple #2
0
/* Reads the page tags
 * Returns 1 if successful or -1 on error
 */
int libesedb_page_read_tags(
     libcdata_array_t *page_tags_array,
     libesedb_io_handle_t *io_handle,
     uint16_t number_of_page_tags,
     uint8_t *page_data,
     size_t page_data_size,
     libcerror_error_t **error )
{
	libesedb_page_tags_value_t *page_tags_value = NULL;
	uint8_t *page_tags_data                     = NULL;
	static char *function                       = "libesedb_page_read_tags";
	uint16_t page_tag_offset                    = 0;
	uint16_t page_tag_size                      = 0;
	uint16_t page_tags_index                    = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	size_t page_tags_data_size                  = 0;
#endif

	if( page_tags_array == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid page tags array.",
		 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( page_data == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid page data.",
		 function );

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

		return( -1 );
	}
	if( libcdata_array_resize(
	     page_tags_array,
	     number_of_page_tags,
	     (int (*)(intptr_t **, libcerror_error_t **)) &libesedb_page_tags_value_free,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_RESIZE_FAILED,
		 "%s: unable to resize page tags array.",
		 function );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		page_tags_data_size = 4 * number_of_page_tags;

		libcnotify_printf(
		 "%s: page tags:\n",
		 function );
		libcnotify_print_data(
		 &( page_data[ page_data_size - page_tags_data_size ] ),
		 page_tags_data_size,
		 0 );
	}
#endif
	/* Read the page tags back to front
	 */
	page_tags_data = &( page_data[ page_data_size - 2 ] );

	for( page_tags_index = 0;
	     page_tags_index < number_of_page_tags;
	     page_tags_index++ )
	{
		if( libesedb_page_tags_value_initialize(
		     &page_tags_value,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
			 "%s: unable to create page tags value.",
			 function );

			goto on_error;
		}
		byte_stream_copy_to_uint16_little_endian(
		 page_tags_data,
		 page_tag_offset );

		page_tags_data -= 2;

		byte_stream_copy_to_uint16_little_endian(
		 page_tags_data,
		 page_tag_size );

		page_tags_data -= 2;

		if( ( io_handle->format_revision >= LIBESEDB_FORMAT_REVISION_EXTENDED_PAGE_HEADER )
		 && ( io_handle->page_size >= 16384 ) )
		{
			page_tags_value->flags  = 0;
			page_tags_value->offset = page_tag_offset & 0x7fff;
			page_tags_value->size   = page_tag_size & 0x7fff;;
		}
		else
		{
			page_tags_value->flags  = page_tag_offset >> 13;
			page_tags_value->offset = page_tag_offset & 0x1fff;
			page_tags_value->size   = page_tag_size & 0x1fff;
		}
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: page tag: %03" PRIu16 " offset\t\t\t\t: %" PRIu16 " (0x%04" PRIx16 ")\n",
			 function,
			 page_tags_index,
			 page_tags_value->offset,
			 page_tag_offset );

			libcnotify_printf(
			 "%s: page tag: %03" PRIu16 " size\t\t\t\t: %" PRIu16 " (0x%04" PRIx16 ")\n",
			 function,
			 page_tags_index,
			 page_tags_value->size,
			 page_tag_size );

			if( ( io_handle->format_revision < LIBESEDB_FORMAT_REVISION_EXTENDED_PAGE_HEADER )
			 && ( io_handle->page_size < 16384 ) )
			{
				libcnotify_printf(
				 "%s: page tag: %03" PRIu16 " flags\t\t\t\t: 0x%02" PRIx8 "",
				 function,
				 page_tags_index,
				 page_tags_value->flags );
				libesedb_debug_print_page_tag_flags(
				 page_tags_value->flags );
				libcnotify_printf(
				 "\n" );
			}
		}
#endif
		if( libcdata_array_set_entry_by_index(
		     page_tags_array,
		     (int) page_tags_index,
		     (intptr_t *) page_tags_value,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
			 "%s: unable to set page tag: %" PRIu16 ".",
			 function,
			 page_tags_index );

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

on_error:
	if( page_tags_value != NULL )
	{
		libesedb_page_tags_value_free(
		 &page_tags_value,
		 NULL );
	}
	return( -1 );
}
Exemple #3
0
/* Reads bits from the underlying byte stream
 * Returns the number of bytes read, 0 if no data available or -1 on error
 */
ssize_t libfwnt_bit_stream_read(
         libfwnt_bit_stream_t *bit_stream,
         size_t read_size,
         libcerror_error_t **error )
{
	uint32_t bits          = 0;
	static char *function  = "libfwnt_bit_stream_read";
	uint8_t number_of_bits = 0;

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

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

		return( -1 );
	}
	if( ( read_size != 2 )
	 && ( read_size != 4 ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_OUT_OF_BOUNDS,
		 "%s: read size value out of bounds.",
		 function );

		return( -1 );
	}
	if( bit_stream->byte_stream_offset >= bit_stream->byte_stream_size )
	{
		return( 0 );
	}
	if( ( bit_stream->byte_stream_offset + read_size ) > bit_stream->byte_stream_size )
	{
		read_size = bit_stream->byte_stream_size - bit_stream->byte_stream_offset;
	}
	if( read_size == 0 )
	{
		return( 0 );
	}
	number_of_bits = (uint8_t) ( read_size << 3 );

	if( ( number_of_bits + bit_stream->number_of_bits ) > 32 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
		 "%s: number of bits value out of bounds.",
		 function );

		return( -1 );
	}
/* TODO optimize the read for the maximum number of available bytes. ? */
/* TODO what about handling intermediate read size values ? */

	while( number_of_bits >= 16 )
	{
		bit_stream->bits <<= 16;

		byte_stream_copy_to_uint16_little_endian(
		 &( bit_stream->byte_stream[ bit_stream->byte_stream_offset ] ),
		 bits );

		bit_stream->bits               |= bits;
		bit_stream->byte_stream_offset += 2;
		bit_stream->number_of_bits     += 16;

		number_of_bits -= 16;
	}
	return( (ssize_t) read_size );
}
/* Reads key hierarchy entry data
 * Returns 1 if successful or -1 on error
 */
int libcreg_key_hierarchy_entry_read_data(
     libcreg_key_hierarchy_entry_t *key_hierarchy_entry,
     const uint8_t *data,
     size_t data_size,
     size_t data_offset LIBCREG_ATTRIBUTE_UNUSED,
     libcerror_error_t **error )
{
	static char *function = "libcreg_key_hierarchy_entry_read_data";

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

	if( key_hierarchy_entry == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid key hierarchy entry.",
		 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 < sizeof( creg_key_hierarchy_entry_t ) )
	{
		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_ARGUMENTS,
		 LIBCERROR_ARGUMENT_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: key hierarchy entry:\n",
		 function );
		libcnotify_print_data(
		 data,
		 sizeof( creg_key_hierarchy_entry_t ),
		 0 );
	}
#endif
	byte_stream_copy_to_uint32_little_endian(
	 ( (creg_key_hierarchy_entry_t *) data )->name_hash,
	 key_hierarchy_entry->name_hash );

	byte_stream_copy_to_uint32_little_endian(
	 ( (creg_key_hierarchy_entry_t *) data )->parent_key_offset,
	 key_hierarchy_entry->parent_key_offset );

	byte_stream_copy_to_uint32_little_endian(
	 ( (creg_key_hierarchy_entry_t *) data )->sub_key_offset,
	 key_hierarchy_entry->sub_key_offset );

	byte_stream_copy_to_uint32_little_endian(
	 ( (creg_key_hierarchy_entry_t *) data )->next_key_offset,
	 key_hierarchy_entry->next_key_offset );

	byte_stream_copy_to_uint16_little_endian(
	 ( (creg_key_hierarchy_entry_t *) data )->key_name_entry_number,
	 key_hierarchy_entry->key_name_entry_number );

	byte_stream_copy_to_uint16_little_endian(
	 ( (creg_key_hierarchy_entry_t *) data )->data_block_number,
	 key_hierarchy_entry->data_block_number );

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

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

		libcnotify_printf(
		 "%s: name hash\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 key_hierarchy_entry->name_hash );

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

		libcnotify_printf(
		 "%s: parent key offset\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 key_hierarchy_entry->parent_key_offset );

		libcnotify_printf(
		 "%s: sub key offset\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 key_hierarchy_entry->sub_key_offset );

		libcnotify_printf(
		 "%s: next key offset\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 key_hierarchy_entry->next_key_offset );

		libcnotify_printf(
		 "%s: key name entry number\t\t\t: %" PRIi16 "\n",
		 function,
		 (int16_t) key_hierarchy_entry->key_name_entry_number );

		libcnotify_printf(
		 "%s: data block number\t\t\t: %" PRIi16 "\n",
		 function,
		 (int16_t) key_hierarchy_entry->data_block_number );

		libcnotify_printf(
		 "\n" );
	}
#endif
	return( 1 );
}
Exemple #5
0
/* Reads a data block header
 * Returns 1 if successful, 0 if no data block signature was found or -1 on error
 */
int libcreg_data_block_read_header(
     libcreg_data_block_t *data_block,
     libbfio_handle_t *file_io_handle,
     libcerror_error_t **error )
{
	creg_data_block_header_t data_block_header;

	static char *function = "libcreg_data_block_read_header";
	ssize_t read_count    = 0;

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

	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( libbfio_handle_get_offset(
	     file_io_handle,
	     &( data_block->offset ),
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
		 "%s: unable to retrieve file offset.",
		 function );

		return( -1 );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: reading data block header at offset: %" PRIi64 " (0x%08" PRIx64 ")\n",
		 function,
		 data_block->offset,
		 data_block->offset );
	}
#endif
	read_count = libbfio_handle_read_buffer(
	              file_io_handle,
	              (uint8_t *) &data_block_header,
	              sizeof( creg_data_block_header_t ),
	              error );

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

		return( -1 );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: data block header:\n",
		 function );
		libcnotify_print_data(
		 (uint8_t *) &data_block_header,
		 sizeof( creg_data_block_header_t ),
		 0 );
	}
#endif
	if( memory_compare(
	     data_block_header.signature,
	     creg_data_block_signature,
	     4 ) != 0 )
	{
		return( 0 );
	}
	byte_stream_copy_to_uint32_little_endian(
	 data_block_header.size,
	 data_block->size );

	byte_stream_copy_to_uint32_little_endian(
	 data_block_header.unused_size,
	 data_block->unused_size );

	byte_stream_copy_to_uint32_little_endian(
	 data_block_header.used_size,
	 data_block->used_size );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: signature\t\t\t\t: %c%c%c%c\n",
		 function,
		 data_block_header.signature[ 0 ],
		 data_block_header.signature[ 1 ],
		 data_block_header.signature[ 2 ],
		 data_block_header.signature[ 3 ] );

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

		libcnotify_printf(
		 "%s: unused size\t\t\t\t: %" PRIu32 "\n",
		 function,
		 data_block->unused_size );

		byte_stream_copy_to_uint16_little_endian(
		 data_block_header.unknown1,
		 value_16bit );
		libcnotify_printf(
		 "%s: unknown1\t\t\t\t: 0x%04" PRIx16 "\n",
		 function,
		 value_16bit );

		byte_stream_copy_to_uint16_little_endian(
		 data_block_header.index,
		 value_16bit );
		libcnotify_printf(
		 "%s: index\t\t\t\t\t: %" PRIu16 "\n",
		 function,
		 value_16bit );

		libcnotify_printf(
		 "%s: used size\t\t\t\t: %" PRIi32 "\n",
		 function,
		 (int32_t) data_block->used_size );

		byte_stream_copy_to_uint16_little_endian(
		 data_block_header.unknown2,
		 value_16bit );
		libcnotify_printf(
		 "%s: unknown2\t\t\t\t: %" PRIu16 "\n",
		 function,
		 value_16bit );

		byte_stream_copy_to_uint16_little_endian(
		 data_block_header.unknown3,
		 value_16bit );
		libcnotify_printf(
		 "%s: unknown3\t\t\t\t: %" PRIu16 "\n",
		 function,
		 value_16bit );

		libcnotify_printf(
		 "%s: unknown3:\n",
		 function );
		libcnotify_print_data(
		 data_block_header.unknown4,
		 8,
		 0 );

		libcnotify_printf(
		 "\n" );
	}
#endif
/* TODO check if unused_size + used_size == size */
	return( 1 );
}
/* Reads string values
 * Returns 1 if successful or -1 on error
 */
int libwrc_string_values_read(
     libwrc_language_entry_t *language_entry,
     libwrc_io_handle_t *io_handle,
     libbfio_handle_t *file_io_handle,
     uint32_t identifier,
     libwrc_data_descriptor_t *data_descriptor,
     libcerror_error_t **error )
{
	libfvalue_value_t *string_value = NULL;
	uint8_t *resource_data          = NULL;
	uint8_t *string_resource_data   = NULL;
	static char *function           = "libwrc_string_values_read";
	off64_t file_offset             = 0;
	size_t resource_data_size       = 0;
	ssize_t read_count              = 0;
	uint32_t string_identifier      = 0;
	uint32_t string_index           = 0;
	uint32_t string_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 );
	}
	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;
	}
	string_resource_data = resource_data;

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: resource data:\n",
		 function );
		libcnotify_print_data(
		 string_resource_data,
		 resource_data_size,
		 0 );
	}
#endif
	while( resource_data_size > 0 )
	{
		byte_stream_copy_to_uint16_little_endian(
		 string_resource_data,
		 string_size );

		string_resource_data += sizeof( uint16_t );
		resource_data_size   -= sizeof( uint16_t );

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: string: %02" PRIu32 " length\t\t\t\t: %" PRIu32 "\n",
			 function,
			 string_index,
			 string_size );
		}
#endif
		if( string_size > 0 )
		{
			string_identifier = ( identifier << 4 ) | string_index;

			string_size *= 2;

			if( string_size > resource_data_size )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
				 "%s: string size value out of bound.",
				 function );

				goto on_error;
			}
			if( libfvalue_value_type_initialize(
			     &string_value,
			     LIBFVALUE_VALUE_TYPE_STRING_UTF16,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
				 "%s: unable to create string value.",
				 function );

				goto on_error;
			}
			if( libfvalue_value_set_identifier(
			     string_value,
			     (uint8_t *) &string_identifier,
			     4,
			     LIBFVALUE_VALUE_FLAG_IDENTIFIER_MANAGED,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
				 "%s: unable to set identifier of string value.",
				 function );

				goto on_error;
			}
#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: string: %02" PRIu32 " data:\n",
				 function,
				 string_index );
				libcnotify_print_data(
				 string_resource_data,
				 (size_t) string_size,
				 0 );
			}
#endif
			if( libfvalue_value_set_data(
			     string_value,
			     string_resource_data,
			     (size_t) string_size,
			     LIBFVALUE_CODEPAGE_UTF16_LITTLE_ENDIAN,
			     LIBFVALUE_VALUE_DATA_FLAG_MANAGED,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
				 "%s: unable to set data of string value.",
				 function );

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

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

					goto on_error;
				}
				libcnotify_printf(
				 "\n" );
			}
#endif
			string_resource_data += (size_t) string_size;
			resource_data_size   -= (size_t) string_size;

			if( libwrc_language_entry_append_value(
			     language_entry,
			     &value_index,
			     (intptr_t *) string_value,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_APPEND_FAILED,
				 "%s: unable to append string value.",
				 function );

				goto on_error;
			}
			string_value = NULL;
		}
#if defined( HAVE_DEBUG_OUTPUT )
		else if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "\n" );
		}
#endif
		string_index++;
	}
	memory_free(
	 resource_data );

/* TODO validate if number of strings is 16 ? */

	return( 1 );

on_error:
	if( string_value != NULL )
	{
		libfvalue_value_free(
		 &string_value,
		 NULL );
	}
	if( resource_data != NULL )
	{
		memory_free(
		 resource_data );
	}
	return( -1 );
}
Exemple #7
0
/* Reads the record
 * Returns 1 if successful or -1 on error
 */
int libftxf_record_read(
     libftxf_record_t *record,
     const uint8_t *record_data,
     size_t record_data_size,
     libcerror_error_t **error )
{
	libftxf_internal_record_t *internal_record  = NULL;
	static char *function                       = "libftxf_record_read";
	size_t record_data_offset                   = 0;
	uint16_t record_type                        = 0;
	uint16_t name_offset                        = 0;
	uint16_t name_size                          = 0;

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

	libcstring_system_character_t *value_string = NULL;
	libfdatetime_filetime_t *filetime           = NULL;
	libfguid_identifier_t *guid                 = NULL;
	size_t value_string_size                    = 0;
	uint64_t value_64bit                        = 0;
	uint32_t value_32bit                        = 0;
	uint16_t value_16bit                        = 0;
	int result                                  = 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 = (libftxf_internal_record_t *) record;

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

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

		return( -1 );
	}
	if( record_data_size < sizeof( ftxf_record_header_t ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
		 "%s: invalid record data 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(
		 record_data,
		 sizeof( ftxf_record_header_t ),
		 0 );
	}
#endif
	byte_stream_copy_to_uint16_little_endian(
	 ( (ftxf_record_header_t *) record_data )->record_type,
	 record_type );

	byte_stream_copy_to_uint32_little_endian(
	 ( (ftxf_record_header_t *) record_data )->record_size,
	 internal_record->size );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		byte_stream_copy_to_uint32_little_endian(
		 ( (ftxf_record_header_t *) record_data )->unknown1,
		 value_32bit );
		libcnotify_printf(
		 "%s: unknown1\t\t\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		libcnotify_printf(
		 "%s: record type\t\t\t\t\t: 0x%04" PRIx16 "\n",
		 function,
		 record_type );

		byte_stream_copy_to_uint16_little_endian(
		 ( (ftxf_record_header_t *) record_data )->unknown2,
		 value_16bit );
		libcnotify_printf(
		 "%s: unknown2\t\t\t\t\t\t: 0x%04" PRIx16 "\n",
		 function,
		 value_16bit );

		byte_stream_copy_to_uint64_little_endian(
		 ( (ftxf_record_header_t *) record_data )->file_identifier,
		 value_64bit );
		libcnotify_printf(
		 "%s: file identifier\t\t\t\t\t: 0x%08" PRIx64 "\n",
		 function,
		 value_64bit );

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

		byte_stream_copy_to_uint32_little_endian(
		 ( (ftxf_record_header_t *) record_data )->unknown4,
		 value_32bit );
		libcnotify_printf(
		 "%s: unknown4\t\t\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 ( (ftxf_record_header_t *) record_data )->unknown5,
		 value_32bit );
		libcnotify_printf(
		 "%s: unknown5\t\t\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		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,
		     ( (ftxf_record_header_t *) record_data )->unknown6,
		     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;
		}
		if( libfguid_identifier_free(
		     &guid,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
			 "%s: unable to free GUID.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "%s: unknown6 guid\t\t\t\t\t: %" PRIs_LIBCSTRING_SYSTEM "\n",
		 function,
		 guid_string );

		byte_stream_copy_to_uint64_little_endian(
		 ( (ftxf_record_header_t *) record_data )->unknown7,
		 value_64bit );
		libcnotify_printf(
		 "%s: unknown7\t\t\t\t\t\t: 0x%08" PRIx64 "\n",
		 function,
		 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_byte_stream(
		     filetime,
		     ( (ftxf_record_header_t *) record_data )->unknown8,
		     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( LIBCSTRING_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: unknown8 filetime\t\t\t\t\t: %" PRIs_LIBCSTRING_SYSTEM " UTC\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;
		}
		libcnotify_printf(
		 "%s: record size\t\t\t\t\t: %" PRIu32 "\n",
		 function,
		 internal_record->size );

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

		byte_stream_copy_to_uint64_little_endian(
		 ( (ftxf_record_header_t *) record_data )->unknown10,
		 value_64bit );
		libcnotify_printf(
		 "%s: unknown10\t\t\t\t\t\t: 0x%08" PRIx64 "\n",
		 function,
		 value_64bit );

		libcnotify_printf(
		 "\n" );
	}
Exemple #8
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 #9
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 );
	}
/* 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 );
}
Exemple #11
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 );
}
Exemple #12
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;
	}
Exemple #13
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 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 );
}
/* Read the name to id map entry
 * Returns 1 if successful or -1 on error
 */
int libpff_name_to_id_map_entry_read(
     libpff_name_to_id_map_entry_t *name_to_id_map_entry,
     uint8_t *name_to_id_map_entry_data,
     size_t name_to_id_map_entry_data_size LIBPFF_ATTRIBUTE_UNUSED,
     uint8_t *name_to_id_map_class_identifiers_data,
     size_t name_to_id_map_class_identifiers_data_size,
     uint8_t *name_to_id_map_strings_data,
     size_t name_to_id_map_strings_data_size,
     libcerror_error_t **error )
{
	libpff_internal_name_to_id_map_entry_t *internal_name_to_id_map_entry = NULL;
	uint8_t *name_to_id_map_string_data                                   = NULL;
	static char *function                                                 = "libpff_name_to_id_map_entry_read";
	uint32_t name_to_id_map_entry_value                                   = 0;
	uint32_t name_to_id_map_string_size                                   = 0;
	uint16_t name_to_id_map_class_identifier_index                        = 0;
	uint16_t name_to_id_map_entry_type                                    = 0;
	uint16_t name_to_id_map_entry_number                                  = 0;
	int result                                                            = 0;

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

	LIBPFF_UNREFERENCED_PARAMETER( name_to_id_map_entry_data_size )

	if( name_to_id_map_entry == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid name to id map entry.",
		 function );

		return( -1 );
	}
	internal_name_to_id_map_entry = (libpff_internal_name_to_id_map_entry_t *) name_to_id_map_entry;

	if( name_to_id_map_entry_data == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid name to id map entry data.",
		 function );

		return( -1 );
	}
	if( name_to_id_map_class_identifiers_data == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid name to id map class identifier data.",
		 function );

		return( -1 );
	}
	byte_stream_copy_to_uint32_little_endian(
	 ( (pff_name_to_id_map_entry_t *) name_to_id_map_entry_data )->entry_value,
	 name_to_id_map_entry_value );

	byte_stream_copy_to_uint16_little_endian(
	 ( (pff_name_to_id_map_entry_t *) name_to_id_map_entry_data )->entry_type,
	 name_to_id_map_entry_type );

	byte_stream_copy_to_uint16_little_endian(
	 ( (pff_name_to_id_map_entry_t *) name_to_id_map_entry_data )->entry_number,
	 name_to_id_map_entry_number );

	internal_name_to_id_map_entry->identifier = name_to_id_map_entry_number + 0x8000;

	if( name_to_id_map_entry_type > 5 )
	{
		name_to_id_map_class_identifier_index = (uint16_t) ( ( name_to_id_map_entry_type / 2 ) - 3 );

		if( (size_t) ( name_to_id_map_class_identifier_index * 16 ) > name_to_id_map_class_identifiers_data_size )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: invalid name to id map class identifier index value exceeds class identifiers data size.",
			 function );

			goto on_error;
		}
		if( memory_copy(
		     internal_name_to_id_map_entry->guid,
		     &( name_to_id_map_class_identifiers_data[ name_to_id_map_class_identifier_index * 16 ] ),
		     16 ) == NULL )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_MEMORY,
			 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
			 "%s: unable to copy name to id map class identifier.",
			 function );

			 goto on_error;
		}
	}
	else if( name_to_id_map_entry_type == 5 )
	{
		if( memory_copy(
		     internal_name_to_id_map_entry->guid,
		     libfmapi_guid_public_strings,
		     16 ) == NULL )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_MEMORY,
			 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
			 "%s: unable to set public strings class identifier.",
			 function );

			 goto on_error;
		}
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: entry: %03d name to id map entry value\t\t: 0x%08" PRIx32 "\n",
		 function,
		 name_to_id_map_entry_index,
		 name_to_id_map_entry_value );

		if( name_to_id_map_entry_type > 5 )
		{
			libcnotify_printf(
			 "%s: entry: %03d name to id map entry type\t\t: 0x%04" PRIx16 " (class identifier: %02" PRIu16 ", class: %s)\n",
			 function,
			 name_to_id_map_entry_index,
			 name_to_id_map_entry_type,
			 name_to_id_map_class_identifier_index,
			 libfmapi_class_identifier_get_name(
			  internal_name_to_id_map_entry->guid ) );
		}
		else if( name_to_id_map_entry_type == 5 )
		{
			libcnotify_printf(
			 "%s: entry: %03d name to id map entry type\t\t: 0x%04" PRIx16 " (class: %s)\n",
			 function,
			 name_to_id_map_entry_index,
			 name_to_id_map_entry_type,
			 libfmapi_class_identifier_get_name(
			  internal_name_to_id_map_entry->guid ) );
		}
		else
		{
			libcnotify_printf(
			 "%s: entry: %03d name to id map entry type\t\t: 0x%04" PRIx16 "\n",
			 function,
			 name_to_id_map_entry_index,
			 name_to_id_map_entry_type );
		}
		libcnotify_printf(
		 "%s: entry: %03d name to id map entry number\t: 0x%04" PRIx16 " (0x%04" PRIx32 ")\n",
		 function,
		 name_to_id_map_entry_index,
		 name_to_id_map_entry_number,
		 internal_name_to_id_map_entry->identifier );
	}
#endif

	/* The lowest bit of the name to id map entry type signifies
	 * that the name to id map entry value refers to the name to id map string table or the item values
	 */
	if( ( name_to_id_map_entry_type & 0x0001 ) != 0 )
	{
		if( internal_name_to_id_map_entry->string_value != NULL )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
			 "%s: invalid name to id map entry - string value already set.",
			 function );

			goto on_error;
		}
		/* The strings data can be NULL and therefore these bounds are checked on demand
		 */
		if( name_to_id_map_strings_data == NULL )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
			 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
			 "%s: invalid name to id map strings data.",
			 function );

			goto on_error;
		}
		if( ( name_to_id_map_strings_data_size == 0 )
		 || ( name_to_id_map_strings_data_size > (size_t) SSIZE_MAX ) )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: invalid name to id map strings data size value out of bounds.",
			 function );

			goto on_error;
		}
		if( name_to_id_map_entry_value > name_to_id_map_strings_data_size )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: invalid name to id map entry value exceeds strings data size.",
			 function );

			goto on_error;
		}
		name_to_id_map_string_data = &( name_to_id_map_strings_data[ name_to_id_map_entry_value ] );

		byte_stream_copy_to_uint32_little_endian(
		 name_to_id_map_string_data,
		 name_to_id_map_string_size );

		name_to_id_map_string_data += 4;

		internal_name_to_id_map_entry->type = LIBPFF_NAME_TO_ID_MAP_ENTRY_TYPE_STRING;

		if( (size_t) name_to_id_map_string_size <= ( name_to_id_map_strings_data_size - name_to_id_map_entry_value ) )
		{
			result = libpff_value_type_string_contains_zero_bytes(
				  name_to_id_map_string_data,
				  (size_t) name_to_id_map_string_size,
				  error ) ;

			if( result == -1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
				 "%s: unable to determine name to id map entry string contains zero bytes.",
				 function );

				goto on_error;
			}
			else if( result == 0 )
			{
				internal_name_to_id_map_entry->is_ascii_string = 1;
			}
			internal_name_to_id_map_entry->value_size = (size_t) name_to_id_map_string_size;

			internal_name_to_id_map_entry->string_value = (uint8_t *) memory_allocate(
			                                                           sizeof( uint8_t ) * internal_name_to_id_map_entry->value_size );

			if( internal_name_to_id_map_entry->string_value == NULL )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_MEMORY,
				 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
				 "%s: unable to create name to id map entry string.",
				 function );

				goto on_error;
			}
			if( memory_copy(
			     internal_name_to_id_map_entry->string_value,
			     name_to_id_map_string_data,
			     internal_name_to_id_map_entry->value_size ) == NULL )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_MEMORY,
				 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
				 "%s: unable to set name to id map entry string.",
				 function );

				goto on_error;
			}
#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				if( internal_name_to_id_map_entry->is_ascii_string == 0 )
				{
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
					result = libuna_utf16_string_size_from_utf16_stream(
						  internal_name_to_id_map_entry->string_value,
						  internal_name_to_id_map_entry->value_size,
						  LIBPFF_ENDIAN_LITTLE,
						  &( internal_name_to_id_map_entry->debug_string_size ),
						  error );
#else
					result = libuna_utf8_string_size_from_utf16_stream(
						  internal_name_to_id_map_entry->string_value,
						  internal_name_to_id_map_entry->value_size,
						  LIBPFF_ENDIAN_LITTLE,
						  &( internal_name_to_id_map_entry->debug_string_size ),
						  error );
#endif
				}
				else
				{
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
					result = libuna_utf8_string_size_from_byte_stream(
						  internal_name_to_id_map_entry->string_value,
						  internal_name_to_id_map_entry->value_size,
						  LIBUNA_CODEPAGE_ASCII,
						  &( internal_name_to_id_map_entry->debug_string_size ),
						  error );
#else
					result = libuna_utf8_string_size_from_byte_stream(
						  internal_name_to_id_map_entry->string_value,
						  internal_name_to_id_map_entry->value_size,
						  LIBUNA_CODEPAGE_ASCII,
						  &( internal_name_to_id_map_entry->debug_string_size ),
						  error );
#endif
				}
				if( result != 1 )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
					 "%s: unable to determine name to id map entry string size.",
					 function );

					goto on_error;
				}
				internal_name_to_id_map_entry->debug_string = libcstring_system_string_allocate(
				                                               internal_name_to_id_map_entry->debug_string_size );

				if( internal_name_to_id_map_entry->debug_string == NULL )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_MEMORY,
					 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
					 "%s: unable to create UTF-8 name to id map entry string.",
					 function );

					goto on_error;
				}
				if( internal_name_to_id_map_entry->is_ascii_string == 0 )
				{
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
					result = libuna_utf16_string_copy_from_utf16_stream(
						  (libuna_utf16_character_t *) internal_name_to_id_map_entry->debug_string,
						  internal_name_to_id_map_entry->debug_string_size,
						  internal_name_to_id_map_entry->string_value,
						  internal_name_to_id_map_entry->value_size,
						  LIBPFF_ENDIAN_LITTLE,
						  error );
#else
					result = libuna_utf8_string_copy_from_utf16_stream(
						  (libuna_utf8_character_t *) internal_name_to_id_map_entry->debug_string,
						  internal_name_to_id_map_entry->debug_string_size,
						  internal_name_to_id_map_entry->string_value,
						  internal_name_to_id_map_entry->value_size,
						  LIBPFF_ENDIAN_LITTLE,
						  error );
#endif
				}
				else
				{
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
					result = libuna_utf16_string_copy_from_byte_stream(
						  (libuna_utf16_character_t *) internal_name_to_id_map_entry->debug_string,
						  internal_name_to_id_map_entry->debug_string_size,
						  internal_name_to_id_map_entry->string_value,
						  internal_name_to_id_map_entry->value_size,
						  LIBUNA_CODEPAGE_ASCII,
						  error );
#else
					result = libuna_utf8_string_copy_from_byte_stream(
						  (libuna_utf8_character_t *) internal_name_to_id_map_entry->debug_string,
						  internal_name_to_id_map_entry->debug_string_size,
						  internal_name_to_id_map_entry->string_value,
						  internal_name_to_id_map_entry->value_size,
						  LIBUNA_CODEPAGE_ASCII,
						  error );
#endif
				}
				if( result != 1 )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_CONVERSION,
					 LIBCERROR_CONVERSION_ERROR_GENERIC,
					 "%s: unable to set name to id map entry string.",
					 function );

					goto on_error;
				}
				libcnotify_printf(
				 "%s: entry: %03d name to id map entry string\t: %" PRIs_LIBCSTRING_SYSTEM "\n",
				 function,
				 name_to_id_map_entry_index,
				 internal_name_to_id_map_entry->debug_string );
			}
#endif
		}
		else
		{
#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: invalid name to id map string size value out of bounds.\n",
				 function );
			}
#endif
			/* Since the string does not contain an end-of-string character and the size
			 * does not contain a sane value mark the name to ID map entry as corrupted.
			 */
			internal_name_to_id_map_entry->flags |= LIBPFF_NAME_TO_ID_MAP_ENTRY_FLAG_IS_CORRUPTED;
		}
	}
	else
	{
		internal_name_to_id_map_entry->type          = LIBPFF_NAME_TO_ID_MAP_ENTRY_TYPE_NUMERIC;
		internal_name_to_id_map_entry->numeric_value = name_to_id_map_entry_value;
		internal_name_to_id_map_entry->value_size    = 4;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "\n" );
	}
#endif
	return( 1 );

on_error:
#if defined( HAVE_DEBUG_OUTPUT )
	if( internal_name_to_id_map_entry->debug_string != NULL )
	{
		memory_free(
		 internal_name_to_id_map_entry->debug_string );

		internal_name_to_id_map_entry->debug_string = NULL;
	}
#endif
	return( -1 );
}
Exemple #16
0
/* Reads the file header
 * Returns 1 if successful or -1 on error
 */
int libmdmp_io_handle_read_file_header(
     libmdmp_io_handle_t *io_handle,
     libbfio_handle_t *file_io_handle,
     uint32_t *streams_directory_offset,
     uint32_t *number_of_streams,
     libcerror_error_t **error )
{
	mdmp_file_header_t file_header;

	static char *function = "libmdmp_io_handle_read_file_header";
	ssize_t read_count    = 0;

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

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

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

		return( -1 );
	}
	if( number_of_streams == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid number of streams.",
		 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( mdmp_file_header_t ),
	              error );

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

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

		return( -1 );
	}
	byte_stream_copy_to_uint16_little_endian(
	 file_header.version,
	 io_handle->version );

	byte_stream_copy_to_uint32_little_endian(
	 file_header.number_of_streams,
	 *number_of_streams );

	byte_stream_copy_to_uint32_little_endian(
	 file_header.streams_directory_rva,
	 *streams_directory_offset );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		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: version\t\t\t\t: 0x%04" PRIx16 "\n",
		 function,
		 io_handle->version );

		byte_stream_copy_to_uint16_little_endian(
		 file_header.implementation_version,
		 value_16bit );
		libcnotify_printf(
		 "%s: implementation version\t\t: 0x%04" PRIx16 "\n",
		 function,
		 value_16bit );

		libcnotify_printf(
		 "%s: number of streams\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 *number_of_streams );

		libcnotify_printf(
		 "%s: streams directory RVA\t\t: 0x%08" PRIx32 "\n",
		 function,
		 *streams_directory_offset );

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

/* TODO print date time value */
		byte_stream_copy_to_uint32_little_endian(
		 file_header.timestamp,
		 value_32bit );
		libcnotify_printf(
		 "%s: timestamp\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

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

		libcnotify_printf(
		 "\n" );
	}
#endif
	return( 1 );
}
/* Reads the catalog definition from the definition data
 * Returns 1 if successful or -1 on error
 */
int libesedb_catalog_definition_read(
     libesedb_catalog_definition_t *catalog_definition,
     uint8_t *definition_data,
     size_t definition_data_size,
     int ascii_codepage LIBESEDB_ATTRIBUTE_UNUSED,
     libcerror_error_t **error )
{
	uint8_t *fixed_size_data_type_value_data            = NULL;
	uint8_t *variable_size_data_type_size_data          = NULL;
	uint8_t *variable_size_data_type_value_data         = NULL;
	static char *function                               = "libesedb_catalog_definition_read";
	uint16_t calculated_variable_size_data_types_offset = 0;
	uint16_t data_type_number                           = 0;
	uint16_t previous_variable_size_data_type_size      = 0;
	uint16_t variable_size_data_type_size               = 0;
	uint16_t variable_size_data_types_offset            = 0;
	uint8_t last_fixed_size_data_type                   = 0;
	uint8_t last_variable_size_data_type                = 0;
	uint8_t number_of_variable_size_data_types          = 0;
	uint8_t variable_size_data_type_iterator            = 0;

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

	LIBESEDB_UNREFERENCED_PARAMETER( ascii_codepage )

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

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

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

		return( -1 );
	}
	if( definition_data_size < sizeof( esedb_data_definition_header_t ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
		 "%s: definition data too small.",
		 function );

		return( -1 );
	}
	last_fixed_size_data_type    = ( (esedb_data_definition_header_t *) definition_data )->last_fixed_size_data_type;
	last_variable_size_data_type = ( (esedb_data_definition_header_t *) definition_data )->last_variable_size_data_type;

	byte_stream_copy_to_uint16_little_endian(
	 ( (esedb_data_definition_header_t *) definition_data )->variable_size_data_types_offset,
	 variable_size_data_types_offset );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: last fixed size data type\t\t\t\t: %" PRIu8 "\n",
		 function,
		 last_fixed_size_data_type );

		libcnotify_printf(
		 "%s: last variable size data type\t\t\t\t: %" PRIu8 "\n",
		 function,
		 last_variable_size_data_type );

		libcnotify_printf(
		 "%s: variable size data types offset\t\t\t: %" PRIu16 "\n",
		 function,
		 variable_size_data_types_offset );
	}
#endif

	/* As far as the documentation states
	 * the column data FIELD structure is 16 bytes of size
	 */
	if( last_fixed_size_data_type < 5 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_VALUE_TOO_SMALL,
		 "%s: last fixed size data type too small.",
		 function );

		return( -1 );
	}
	if( last_fixed_size_data_type > 11 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported last fixed size data type: %" PRIu8 ".",
		 function,
		 last_fixed_size_data_type );

		return( -1 );
	}
	if( last_variable_size_data_type > 127 )
	{
		number_of_variable_size_data_types = last_variable_size_data_type - 127;
	}
	calculated_variable_size_data_types_offset += sizeof( esedb_data_definition_header_t );

	/* Use a fall through to determine the size of the fixed size data types
	 */
	switch( last_fixed_size_data_type )
	{
		case 11:
			calculated_variable_size_data_types_offset += 2;
		case 10:
			calculated_variable_size_data_types_offset += 4;
		case 9:
			calculated_variable_size_data_types_offset += 2;
		case 8:
			if( last_variable_size_data_type > 127 )
			{
				calculated_variable_size_data_types_offset += 1 * number_of_variable_size_data_types;
			}
		case 7:
			calculated_variable_size_data_types_offset += 4;
		case 6:
			calculated_variable_size_data_types_offset += 4;
		case 5:
			calculated_variable_size_data_types_offset += 4;
		case 4:
			calculated_variable_size_data_types_offset += 4;
		case 3:
			calculated_variable_size_data_types_offset += 4;
		case 2:
			calculated_variable_size_data_types_offset += 2;
		case 1:
			calculated_variable_size_data_types_offset += 4;
			break;
	}
	if( variable_size_data_types_offset > definition_data_size )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
		 "%s: variable size data types offset exceeds definition data.",
		 function );

		return( -1 );
	}
	fixed_size_data_type_value_data = &( definition_data[ sizeof( esedb_data_definition_header_t ) ] );

	byte_stream_copy_to_uint32_little_endian(
	 ( (esedb_data_definition_t *) fixed_size_data_type_value_data )->father_data_page_object_identifier,
	 catalog_definition->father_data_page_object_identifier );

	byte_stream_copy_to_uint16_little_endian(
	 ( (esedb_data_definition_t *) fixed_size_data_type_value_data )->type,
	 catalog_definition->type );

	byte_stream_copy_to_uint32_little_endian(
	 ( (esedb_data_definition_t *) fixed_size_data_type_value_data )->identifier,
	 catalog_definition->identifier );

	if( catalog_definition->type == LIBESEDB_CATALOG_DEFINITION_TYPE_COLUMN )
	{
		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_data_definition_t *) fixed_size_data_type_value_data )->column_type,
		 catalog_definition->column_type );
	}
	else
	{
		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_data_definition_t *) fixed_size_data_type_value_data )->father_data_page_number,
		 catalog_definition->father_data_page_number );
	}
	byte_stream_copy_to_uint32_little_endian(
	 ( (esedb_data_definition_t *) fixed_size_data_type_value_data )->space_usage,
	 catalog_definition->size );

	if( catalog_definition->type == LIBESEDB_CATALOG_DEFINITION_TYPE_COLUMN )
	{
		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_data_definition_t *) fixed_size_data_type_value_data )->codepage,
		 catalog_definition->codepage );
	}
	if( last_fixed_size_data_type >= 10 )
	{
		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_data_definition_t *) fixed_size_data_type_value_data )->lc_map_flags,
		 catalog_definition->lcmap_flags );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		data_type_number = 1;

		libcnotify_printf(
		 "%s: (%03" PRIu16 ") father data page (FDP) object identifier\t: %" PRIu32 "\n",
		 function,
		 data_type_number++,
		 catalog_definition->father_data_page_object_identifier );

		libcnotify_printf(
		 "%s: (%03" PRIu16 ") type\t\t\t\t\t\t: 0x%04" PRIx16 " ",
		 function,
		 data_type_number++,
		 catalog_definition->type );
		libesedb_debug_print_page_value_definition_type(
		 catalog_definition->type );
		libcnotify_printf(
		 "\n" );

		libcnotify_printf(
		 "%s: (%03" PRIu16 ") identifier\t\t\t\t\t: %" PRIu32 "\n",
		 function,
		 data_type_number++,
		 catalog_definition->identifier );

		if( catalog_definition->type == LIBESEDB_CATALOG_DEFINITION_TYPE_COLUMN )
		{
			libcnotify_printf(
			 "%s: (%03" PRIu16 ") column type\t\t\t\t\t: %" PRIu32 " (%s) %s\n",
			 function,
			 data_type_number++,
			 catalog_definition->column_type,
			 libesedb_column_type_get_identifier(
			  catalog_definition->column_type ),
			 libesedb_column_type_get_description(
			  catalog_definition->column_type ) );
		}
		else
		{
			libcnotify_printf(
			 "%s: (%03" PRIu16 ") father data page (FDP) number\t\t\t: %" PRIu32 "\n",
			 function,
			 data_type_number++,
			 catalog_definition->father_data_page_number );
		}
		libcnotify_printf(
		 "%s: (%03" PRIu16 ") space usage\t\t\t\t\t: %" PRIu32 "\n",
		 function,
		 data_type_number++,
		 catalog_definition->size );

		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_data_definition_t *) fixed_size_data_type_value_data )->flags,
		 value_32bit );

		if( last_fixed_size_data_type >= 6 )
		{
			if( catalog_definition->type == LIBESEDB_CATALOG_DEFINITION_TYPE_COLUMN )
			{
				libcnotify_printf(
				 "%s: (%03" PRIu16 ") flags\t\t\t\t\t\t: 0x%08" PRIx32 "\n",
				 function,
				 data_type_number++,
				 value_32bit );
				libesedb_debug_print_column_group_of_bits(
				 value_32bit );
				libcnotify_printf(
				 "\n" );
			}
			else if( catalog_definition->type == LIBESEDB_CATALOG_DEFINITION_TYPE_INDEX )
			{
				libcnotify_printf(
				 "%s: (%03" PRIu16 ") flags\t\t\t\t\t\t: 0x%08" PRIx32 "\n",
				 function,
				 data_type_number++,
				 value_32bit );
				libesedb_debug_print_index_group_of_bits(
				 value_32bit );
				libcnotify_printf(
				 "\n" );
			}
			else
			{
				libcnotify_printf(
				 "%s: (%03" PRIu16 ") flags\t\t\t\t\t\t: 0x%08" PRIx32 "\n",
				 function,
				 data_type_number++,
				 value_32bit );
			}
		}
		if( last_fixed_size_data_type >= 7 )
		{
			if( catalog_definition->type == LIBESEDB_CATALOG_DEFINITION_TYPE_COLUMN )
			{
				libcnotify_printf(
				 "%s: (%03" PRIu16 ") codepage\t\t\t\t\t: %" PRIu32 "",
				 function,
				 data_type_number++,
				 catalog_definition->codepage );

				if( catalog_definition->codepage != 0 )
				{
					libcnotify_printf(
					 " (%s) %s",
					 libesedb_codepage_get_identifier(
					  catalog_definition->codepage ),
					 libesedb_codepage_get_description(
					  catalog_definition->codepage ) );
				}
				libcnotify_printf(
				 "\n" );
			}
			else if( catalog_definition->type == LIBESEDB_CATALOG_DEFINITION_TYPE_INDEX )
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (esedb_data_definition_t *) fixed_size_data_type_value_data )->locale_identifier,
				 value_32bit );

				libcnotify_printf(
				 "%s: (%03" PRIu16 ") locale identifier\t\t\t\t: 0x%08" PRIx32 " (%s)\n",
				 function,
				 data_type_number++,
				 value_32bit,
				 libesedb_lcid_language_tag_get_identifier(
				  (uint16_t) value_32bit ),
				 libesedb_lcid_language_tag_get_description(
				  (uint16_t) value_32bit ) );
			}
			else
			{
				byte_stream_copy_to_uint32_little_endian(
				 ( (esedb_data_definition_t *) fixed_size_data_type_value_data )->number_of_pages,
				 value_32bit );

				libcnotify_printf(
				 "%s: (%03" PRIu16 ") number of pages\t\t\t\t\t: %" PRIu32 "\n",
				 function,
				 data_type_number++,
				 value_32bit );
			}
		}
		if( last_fixed_size_data_type >= 8 )
		{
			libcnotify_printf(
			 "%s: (%03" PRIu16 ") root flag\t\t\t\t\t: 0x%02" PRIx8 "\n",
			 function,
			 data_type_number++,
			 ( (esedb_data_definition_t *) fixed_size_data_type_value_data )->root_flag );
		}
		if( last_fixed_size_data_type >= 9 )
		{
			byte_stream_copy_to_uint16_little_endian(
			 ( (esedb_data_definition_t *) fixed_size_data_type_value_data )->record_offset,
			 record_offset );

			libcnotify_printf(
			 "%s: (%03" PRIu16 ") record offset\t\t\t\t\t: %" PRIu16 "\n",
			 function,
			 data_type_number++,
			 record_offset );
		}
		if( last_fixed_size_data_type >= 10 )
		{
			libcnotify_printf(
			 "%s: (%03" PRIu16 ") locale map (LCMAP) flags\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 data_type_number++,
			 catalog_definition->lcmap_flags );
			libesedb_debug_print_lcmap_flags(
			 catalog_definition->lcmap_flags );
			libcnotify_printf(
			 "\n" );
		}
		if( last_fixed_size_data_type >= 11 )
		{
			byte_stream_copy_to_uint16_little_endian(
			 ( (esedb_data_definition_t *) fixed_size_data_type_value_data )->key_most,
			 value_16bit );

			libcnotify_printf(
			 "%s: (%03" PRIu16 ") key most\t\t\t\t\t: 0x04%" PRIx16 "\n",
			 function,
			 data_type_number++,
			 value_16bit );
		}
		libcnotify_printf(
		 "\n" );
	}
#endif

#if defined( HAVE_DEBUG_OUTPUT )
	if( ( libcnotify_verbose != 0 )
	 && ( variable_size_data_types_offset > calculated_variable_size_data_types_offset ) )
	{
		libcnotify_printf(
		 "%s: trailing data:\n",
		 function );
		libcnotify_print_data(
		 &( definition_data[ calculated_variable_size_data_types_offset ] ),
		 variable_size_data_types_offset - calculated_variable_size_data_types_offset,
		 0 );
	}
#endif
	if( number_of_variable_size_data_types > 0 )
	{
		variable_size_data_type_size_data  = &( definition_data[ variable_size_data_types_offset ] );
		variable_size_data_type_value_data = &( variable_size_data_type_size_data[ number_of_variable_size_data_types * 2 ] );

		data_type_number = 128;

		for( variable_size_data_type_iterator = 0;
		     variable_size_data_type_iterator < number_of_variable_size_data_types;
		     variable_size_data_type_iterator++ )
		{
			byte_stream_copy_to_uint16_little_endian(
			 variable_size_data_type_size_data,
			 variable_size_data_type_size );

			variable_size_data_type_size_data += 2;

#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: (%03" PRIu16 ") variable size data type size\t\t\t: 0x%04" PRIx16 " (%" PRIu16 ")\n",
				 function,
				 data_type_number,
				 variable_size_data_type_size,
				 ( ( variable_size_data_type_size & 0x8000 ) != 0 ) ? 0 : ( variable_size_data_type_size & 0x7fff ) - previous_variable_size_data_type_size );
			}
#endif

			switch( data_type_number )
			{
				case 128:
					/* The MSB signifies that the variable size data type is empty
					 */
					if( ( variable_size_data_type_size & 0x8000 ) == 0 )
					{
						catalog_definition->name_size = (size_t) ( variable_size_data_type_size - previous_variable_size_data_type_size );

						catalog_definition->name = (uint8_t *) memory_allocate(
										        sizeof( uint8_t ) * catalog_definition->name_size );

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

							catalog_definition->name_size = 0;

							return( -1 );
						}
						if( memory_copy(
						     catalog_definition->name,
						     &( variable_size_data_type_value_data[ previous_variable_size_data_type_size ] ),
						     catalog_definition->name_size ) == NULL )
						{
							libcerror_error_set(
							 error,
							 LIBCERROR_ERROR_DOMAIN_MEMORY,
							 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
							 "%s: unable to set name.",
							 function );

							memory_free(
							 catalog_definition->name );

							catalog_definition->name      = NULL;
							catalog_definition->name_size = 0;

							return( -1 );
						}
#if defined( HAVE_DEBUG_OUTPUT )
						if( libcnotify_verbose != 0 )
						{
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
							result = libuna_utf16_string_size_from_byte_stream(
							          catalog_definition->name,
							          catalog_definition->name_size,
							          ascii_codepage,
							          &value_string_size,
							          error );
#else
							result = libuna_utf8_string_size_from_byte_stream(
							          catalog_definition->name,
							          catalog_definition->name_size,
							          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 name string.",
								 function );

								return( -1 );
							}
							catalog_definition->name_string = libcstring_system_string_allocate(
							                                   value_string_size );

							if( catalog_definition->name_string == NULL )
							{
								libcerror_error_set(
								 error,
								 LIBCERROR_ERROR_DOMAIN_MEMORY,
								 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
								 "%s: unable to create name string.",
								 function );

								return( -1 );
							}
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
							result = libuna_utf16_string_copy_from_byte_stream(
							          (libuna_utf16_character_t *) catalog_definition->name_string,
							          value_string_size,
							          catalog_definition->name,
							          catalog_definition->name_size,
							          ascii_codepage,
							          error );
#else
							result = libuna_utf8_string_copy_from_byte_stream(
							          (libuna_utf8_character_t *) catalog_definition->name_string,
							          value_string_size,
							          catalog_definition->name,
							          catalog_definition->name_size,
							          ascii_codepage,
							          error );
#endif

							if( result != 1 )
							{
								libcerror_error_set(
								 error,
								 LIBCERROR_ERROR_DOMAIN_CONVERSION,
								 LIBCERROR_CONVERSION_ERROR_GENERIC,
								 "%s: unable to set name string.",
								 function );

								memory_free(
								 catalog_definition->name_string );

								catalog_definition->name_string = NULL;

								return( -1 );
							}
							libcnotify_printf(
							 "%s: (%03" PRIu8 ") name\t\t\t\t\t\t: %" PRIs_LIBCSTRING_SYSTEM "\n",
							 function,
							 data_type_number,
							 catalog_definition->name_string );
						}
#endif
					}
#if defined( HAVE_DEBUG_OUTPUT )
					else if( libcnotify_verbose != 0 )
					{
						libcnotify_printf(
						 "%s: (%03" PRIu8 ") name\t\t\t\t\t\t: <NULL>\n",
						 function,
						 data_type_number );
					}
#endif
					break;

#if defined( HAVE_DEBUG_OUTPUT )
				case 129:
					if( libcnotify_verbose != 0 )
					{
						/* The MSB signifies that the variable size data type is empty
						 */
						if( ( variable_size_data_type_size & 0x8000 ) == 0 )
						{
							libcnotify_printf(
							 "%s: (%03" PRIu8 ") stats:\n",
							 function,
							 data_type_number );
							libcnotify_print_data(
							 &( variable_size_data_type_value_data[ previous_variable_size_data_type_size ] ),
							 variable_size_data_type_size - previous_variable_size_data_type_size,
							 0 );
						}
						else
						{
							libcnotify_printf(
							 "%s: (%03" PRIu8 ") stats\t\t\t\t\t\t: <NULL>\n",
							 function,
							 data_type_number );
						}
					}
					break;
#endif

				case 130:
					/* The MSB signifies that the variable size data type is empty
					 */
					if( ( variable_size_data_type_size & 0x8000 ) == 0 )
					{
						catalog_definition->template_name_size = (size_t) ( variable_size_data_type_size - previous_variable_size_data_type_size );

						catalog_definition->template_name = (uint8_t *) memory_allocate(
						                                                 sizeof( uint8_t ) * catalog_definition->template_name_size );

						if( catalog_definition->template_name == NULL )
						{
							libcerror_error_set(
							 error,
							 LIBCERROR_ERROR_DOMAIN_MEMORY,
							 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
							 "%s: unable to create template name.",
							 function );

							catalog_definition->template_name_size = 0;

							return( -1 );
						}
						if( memory_copy(
						     catalog_definition->template_name,
						     &( variable_size_data_type_value_data[ previous_variable_size_data_type_size ] ),
						     catalog_definition->template_name_size ) == NULL )
						{
							libcerror_error_set(
							 error,
							 LIBCERROR_ERROR_DOMAIN_MEMORY,
							 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
							 "%s: unable to set template name.",
							 function );

							memory_free(
							 catalog_definition->template_name );

							catalog_definition->template_name      = NULL;
							catalog_definition->template_name_size = 0;

							return( -1 );
						}
#if defined( HAVE_DEBUG_OUTPUT )
						if( libcnotify_verbose != 0 )
						{
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
							result = libuna_utf16_string_size_from_byte_stream(
							          catalog_definition->template_name,
							          catalog_definition->template_name_size,
							          ascii_codepage,
							          &value_string_size,
							          error );
#else
							result = libuna_utf8_string_size_from_byte_stream(
							          catalog_definition->template_name,
							          catalog_definition->template_name_size,
							          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 template name string.",
								 function );

								return( -1 );
							}
							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 template name string.",
								 function );

								return( -1 );
							}
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
							result = libuna_utf16_string_copy_from_byte_stream(
							          (libuna_utf16_character_t *) value_string,
							          value_string_size,
							          catalog_definition->template_name,
							          catalog_definition->template_name_size,
							          ascii_codepage,
							          error );
#else
							result = libuna_utf8_string_copy_from_byte_stream(
							          (libuna_utf8_character_t *) value_string,
							          value_string_size,
							          catalog_definition->template_name,
							          catalog_definition->template_name_size,
							          ascii_codepage,
							          error );
#endif

							if( result != 1 )
							{
								libcerror_error_set(
								 error,
								 LIBCERROR_ERROR_DOMAIN_CONVERSION,
								 LIBCERROR_CONVERSION_ERROR_GENERIC,
								 "%s: unable to set template name string.",
								 function );

								memory_free(
								 value_string );

								return( -1 );
							}
							libcnotify_printf(
							 "%s: (%03" PRIu8 ") template name\t\t\t\t\t: %" PRIs_LIBCSTRING_SYSTEM "\n",
							 function,
							 data_type_number,
							 value_string );

							memory_free(
							 value_string );
						}
#endif
					}
#if defined( HAVE_DEBUG_OUTPUT )
					else if( libcnotify_verbose != 0 )
					{
						libcnotify_printf(
						 "%s: (%03" PRIu8 ") template name\t\t\t\t\t: <NULL>\n",
						 function,
						 data_type_number );
					}
#endif
					break;

				case 131:
					/* The MSB signifies that the variable size data type is empty
					 */
					if( ( variable_size_data_type_size & 0x8000 ) == 0 )
					{
						catalog_definition->default_value_size = (size_t) ( variable_size_data_type_size - previous_variable_size_data_type_size );

						catalog_definition->default_value = (uint8_t *) memory_allocate(
												 sizeof( uint8_t ) * catalog_definition->default_value_size );

						if( catalog_definition->default_value == NULL )
						{
							libcerror_error_set(
							 error,
							 LIBCERROR_ERROR_DOMAIN_MEMORY,
							 LIBCERROR_MEMORY_ERROR_INSUFFICIENT,
							 "%s: unable to create default value.",
							 function );

							catalog_definition->default_value_size = 0;

							return( -1 );
						}
						if( memory_copy(
						     catalog_definition->default_value,
						     &( variable_size_data_type_value_data[ previous_variable_size_data_type_size ] ),
						     catalog_definition->default_value_size ) == NULL )
						{
							libcerror_error_set(
							 error,
							 LIBCERROR_ERROR_DOMAIN_MEMORY,
							 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
							 "%s: unable to set default value.",
							 function );

							memory_free(
							 catalog_definition->default_value );

							catalog_definition->default_value      = NULL;
							catalog_definition->default_value_size = 0;

							return( -1 );
						}
#if defined( HAVE_DEBUG_OUTPUT )
						if( libcnotify_verbose != 0 )
						{
							libcnotify_printf(
							 "%s: (%03" PRIu8 ") default value:\n",
							 function,
							 data_type_number );
							libcnotify_print_data(
							 catalog_definition->default_value,
							 catalog_definition->default_value_size,
							 0 );
						}
#endif
					}
#if defined( HAVE_DEBUG_OUTPUT )
					else if( libcnotify_verbose != 0 )
					{
						libcnotify_printf(
						 "%s: (%03" PRIu8 ") default value\t\t\t\t\t: <NULL>\n",
						 function,
						 data_type_number );
					}
#endif
					break;

#if defined( HAVE_DEBUG_OUTPUT )
				case 132:
					if( libcnotify_verbose != 0 )
					{
						/* The MSB signifies that the variable size data type is empty
						 */
						if( ( variable_size_data_type_size & 0x8000 ) == 0 )
						{
							libcnotify_printf(
							 "%s: (%03" PRIu8 ") KeyFldIDs:\n",
							 function,
							 data_type_number );
							libcnotify_print_data(
							 &( variable_size_data_type_value_data[ previous_variable_size_data_type_size ] ),
							 variable_size_data_type_size - previous_variable_size_data_type_size,
							 0 );
						}
						else
						{
							libcnotify_printf(
							 "%s: (%03" PRIu8 ") KeyFldIDs\t\t\t\t\t: <NULL>\n",
							 function,
							 data_type_number );
						}
					}
					break;

				case 133:
					if( libcnotify_verbose != 0 )
					{
						/* The MSB signifies that the variable size data type is empty
						 */
						if( ( variable_size_data_type_size & 0x8000 ) == 0 )
						{
							libcnotify_printf(
							 "%s: (%03" PRIu8 ") VarSegMac:\n",
							 function,
							 data_type_number );
							libcnotify_print_data(
							 &( variable_size_data_type_value_data[ previous_variable_size_data_type_size ] ),
							 variable_size_data_type_size - previous_variable_size_data_type_size,
							 0 );
						}
						else
						{
							libcnotify_printf(
							 "%s: (%03" PRIu8 ") VarSegMac\t\t\t\t\t: <NULL>\n",
							 function,
							 data_type_number );
						}
					}
					break;

				case 134:
					if( libcnotify_verbose != 0 )
					{
						/* The MSB signifies that the variable size data type is empty
						 */
						if( ( variable_size_data_type_size & 0x8000 ) == 0 )
						{
							libcnotify_printf(
							 "%s: (%03" PRIu8 ") ConditionalColumns:\n",
							 function,
							 data_type_number );
							libcnotify_print_data(
							 &( variable_size_data_type_value_data[ previous_variable_size_data_type_size ] ),
							 variable_size_data_type_size - previous_variable_size_data_type_size,
							 0 );
						}
						else
						{
							libcnotify_printf(
							 "%s: (%03" PRIu8 ") ConditionalColumns\t\t\t\t: <NULL>\n",
							 function,
							 data_type_number );
						}
					}
					break;

				case 135:
					if( libcnotify_verbose != 0 )
					{
						/* The MSB signifies that the variable size data type is empty
						 */
						if( ( variable_size_data_type_size & 0x8000 ) == 0 )
						{
							libcnotify_printf(
							 "%s: (%03" PRIu8 ") TupleLimits:\n",
							 function,
							 data_type_number );
							libcnotify_print_data(
							 &( variable_size_data_type_value_data[ previous_variable_size_data_type_size ] ),
							 variable_size_data_type_size - previous_variable_size_data_type_size,
							 0 );
						}
						else
						{
							libcnotify_printf(
							 "%s: (%03" PRIu8 ") TupleLimits\t\t\t\t\t: <NULL>\n",
							 function,
							 data_type_number );
						}
					}
					break;

				case 136:
					if( libcnotify_verbose != 0 )
					{
						/* The MSB signifies that the variable size data type is empty
						 */
						if( ( variable_size_data_type_size & 0x8000 ) == 0 )
						{
							libcnotify_printf(
							 "%s: (%03" PRIu8 ") Version:\n",
							 function,
							 data_type_number );
							libcnotify_print_data(
							 &( variable_size_data_type_value_data[ previous_variable_size_data_type_size ] ),
							 variable_size_data_type_size - previous_variable_size_data_type_size,
							 0 );
						}
						else
						{
							libcnotify_printf(
							 "%s: (%03" PRIu8 ") Version\t\t\t\t\t\t: <NULL>\n",
							 function,
							 data_type_number );
						}
					}
					break;
#endif

				default:
#if defined( HAVE_DEBUG_OUTPUT )
					if( libcnotify_verbose != 0 )
					{
						/* The MSB signifies that the variable size data type is empty
						 */
						if( ( variable_size_data_type_size & 0x8000 ) == 0 )
						{
							libcnotify_printf(
							 "%s: (%03" PRIu16 ") variable size data type:\n",
							 function,
							 data_type_number );
							libcnotify_print_data(
							 &( variable_size_data_type_value_data[ previous_variable_size_data_type_size ] ),
							 variable_size_data_type_size - previous_variable_size_data_type_size,
							 0 );
						}
						else
						{
							libcnotify_printf(
							 "%s: (%03" PRIu16 ") variable size data type\t\t\t: <NULL>\n",
							 function,
							 data_type_number );
						}
					}
#endif
					break;
			}
			/* The MSB signifies that the variable size data type is empty
			 */
			if( ( variable_size_data_type_size & 0x8000 ) == 0 )
			{
				previous_variable_size_data_type_size = variable_size_data_type_size;
			}
			data_type_number++;
		}
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "\n" );
	}
#endif

	return( 1 );
}
/* Reads a volume master key from the metadata entry
 * Returns 1 if successful or -1 on error
 */
int libbde_volume_master_key_read(
     libbde_volume_master_key_t *volume_master_key,
     libbde_metadata_entry_t *metadata_entry,
     libcerror_error_t **error )
{
	libbde_aes_ccm_encrypted_key_t *aes_ccm_encrypted_key = NULL;
	libbde_key_t *key                                     = NULL;
	libbde_metadata_entry_t *property_metadata_entry      = NULL;
	libbde_stretch_key_t *stretch_key                     = NULL;
	uint8_t *value_data                                   = NULL;
	static char *function                                 = "libbde_volume_master_key_read";
	size_t value_data_size                                = 0;
	ssize_t read_count                                    = 0;
	int property_metadata_entry_index                     = 0;

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

	libfdatetime_filetime_t *filetime                     = NULL;
	libfguid_identifier_t *guid                           = NULL;
	uint16_t value_16bit                                  = 0;
	int result                                            = 0;
#endif

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

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

		return( -1 );
	}
	if( metadata_entry->value_type != LIBBDE_VALUE_TYPE_VOLUME_MASTER_KEY )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: invalid metadata entry - unsupported value type: 0x%04" PRIx16 ".",
		 function,
		 metadata_entry->value_type );

		return( -1 );
	}
	value_data      = metadata_entry->value_data;
	value_data_size = metadata_entry->value_data_size;

	if( value_data_size < sizeof( bde_metadata_entry_volume_master_key_header_t ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
		 "%s: value data size value out of bounds.",
		 function );

		return( -1 );
	}
	if( memory_copy(
	     volume_master_key->identifier,
	     ( (bde_metadata_entry_volume_master_key_header_t *) value_data )->identifier,
	     16 ) == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_MEMORY,
		 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
		 "%s: unable to copy volume identifier.",
		 function );

		goto on_error;
	}
	byte_stream_copy_to_uint16_little_endian(
	 ( (bde_metadata_entry_volume_master_key_header_t *) value_data )->protection_type,
	 volume_master_key->protection_type );

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

			goto on_error;
		}
		if( libfguid_identifier_copy_from_byte_stream(
		     guid,
		     ( (bde_metadata_entry_volume_master_key_header_t *) value_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( 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_byte_stream(
		     filetime,
		     ( (bde_metadata_entry_volume_master_key_header_t *) value_data )->modification_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( 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_SET_FAILED,
			 "%s: unable to copy filetime to string.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "%s: modification time\t\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;
		}
		byte_stream_copy_to_uint16_little_endian(
		 ( (bde_metadata_entry_volume_master_key_header_t *) value_data )->unknown1,
		 value_16bit );
		libcnotify_printf(
		 "%s: unknown1\t\t\t\t\t: %" PRIu16 "\n",
		 function,
		 value_16bit );

		libcnotify_printf(
		 "%s: protection type\t\t\t\t: 0x%04" PRIx16 " (%s)\n",
		 function,
		 volume_master_key->protection_type,
		 libbde_debug_print_key_protection_type(
		  volume_master_key->protection_type ) );

		libcnotify_printf(
		 "\n" );
	}
#endif
	value_data      += sizeof( bde_metadata_entry_volume_master_key_header_t );
	value_data_size -= sizeof( bde_metadata_entry_volume_master_key_header_t );

	while( value_data_size >= sizeof( bde_metadata_entry_v1_t ) )
	{
		if( memory_compare(
		     value_data,
		     libbde_metadata_entry_empty,
		     sizeof( bde_metadata_entry_v1_t ) ) == 0 )
		{
			break;
		}
		if( libbde_metadata_entry_initialize(
		     &property_metadata_entry,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
			 "%s: unable to create property metadata entry.",
			 function );

			goto on_error;
		}
		read_count = libbde_metadata_entry_read(
			      property_metadata_entry,
			      value_data,
			      value_data_size,
			      error );

		if( read_count == -1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read property metadata entry.",
			 function );

			goto on_error;
		}
		value_data      += read_count;
		value_data_size -= read_count;

		if( property_metadata_entry->value_type == LIBBDE_VALUE_TYPE_KEY )
		{
			if( libbde_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( libbde_key_read(
			     key,
			     property_metadata_entry,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_IO,
				 LIBCERROR_IO_ERROR_READ_FAILED,
				 "%s: unable to read key metadata entry.",
				 function );

				goto on_error;
			}
			if( volume_master_key->key == NULL )
			{
				volume_master_key->key = key;

				key = NULL;
			}
			if( key != NULL )
			{
				if( libbde_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;
				}
			}
		}
		else if( property_metadata_entry->value_type == LIBBDE_VALUE_TYPE_UNICODE_STRING )
		{
#if defined( HAVE_DEBUG_OUTPUT )
			if( libbde_metadata_entry_read_string(
			     property_metadata_entry,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_IO,
				 LIBCERROR_IO_ERROR_READ_FAILED,
				 "%s: unable to read string from property metadata entry.",
				 function );

				goto on_error;
			}
#endif
			if( volume_master_key->string_entry == NULL )
			{
				volume_master_key->string_entry = property_metadata_entry;
			}
		}
		else if( property_metadata_entry->value_type == LIBBDE_VALUE_TYPE_STRETCH_KEY )
		{
			if( libbde_stretch_key_initialize(
			     &stretch_key,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
				 "%s: unable to create stretch key.",
				 function );

				goto on_error;
			}
			if( libbde_stretch_key_read(
			     stretch_key,
			     property_metadata_entry,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_IO,
				 LIBCERROR_IO_ERROR_READ_FAILED,
				 "%s: unable to read stretch key metadata entry.",
				 function );

				goto on_error;
			}
			if( volume_master_key->stretch_key == NULL )
			{
				volume_master_key->stretch_key = stretch_key;

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

					goto on_error;
				}
			}
		}
		else if( property_metadata_entry->value_type == LIBBDE_VALUE_TYPE_AES_CCM_ENCRYPTED_KEY )
		{
			if( libbde_aes_ccm_encrypted_key_initialize(
			     &aes_ccm_encrypted_key,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
				 "%s: unable to create AES-CCM encrypted key.",
				 function );

				goto on_error;
			}
			if( libbde_aes_ccm_encrypted_key_read(
			     aes_ccm_encrypted_key,
			     property_metadata_entry,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_IO,
				 LIBCERROR_IO_ERROR_READ_FAILED,
				 "%s: unable to read AES-CCM encrypted key from property metadata entry.",
				 function );

				goto on_error;
			}
			if( volume_master_key->aes_ccm_encrypted_key == NULL )
			{
				volume_master_key->aes_ccm_encrypted_key = aes_ccm_encrypted_key;

				aes_ccm_encrypted_key = NULL;
			}
			if( aes_ccm_encrypted_key != NULL )
			{
				if( libbde_aes_ccm_encrypted_key_free(
				     &aes_ccm_encrypted_key,
				     error ) != 1 )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
					 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
					 "%s: unable to free AES-CCM encrypted key.",
					 function );

					goto on_error;
				}
			}
		}
		if( libcdata_array_append_entry(
		     volume_master_key->entries_array,
		     &property_metadata_entry_index,
		     (intptr_t *) property_metadata_entry,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
			 "%s: unable to append property metadata entry to entries array.",
			 function );

			goto on_error;
		}
		property_metadata_entry = NULL;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		if( value_data_size > 0 )
		{
			libcnotify_printf(
			 "%s: trailing data:\n",
			 function );
			libcnotify_print_data(
			 value_data,
			 value_data_size,
			 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
		}
	}
#endif
	return( 1 );

on_error:
#if defined( HAVE_DEBUG_OUTPUT )
	if( guid != NULL )
	{
		libfguid_identifier_free(
		 &guid,
		 NULL );
	}
	if( filetime != NULL )
	{
		libfdatetime_filetime_free(
		 &filetime,
		 NULL );
	}
#endif
	if( aes_ccm_encrypted_key != NULL )
	{
		libbde_aes_ccm_encrypted_key_free(
		 &aes_ccm_encrypted_key,
		 NULL );
	}
	if( stretch_key != NULL )
	{
		libbde_stretch_key_free(
		 &stretch_key,
		 NULL );
	}
	if( key != NULL )
	{
		libbde_key_free(
		 &key,
		 NULL );
	}
	if( property_metadata_entry != NULL )
	{
		libbde_metadata_entry_free(
		 &property_metadata_entry,
		 NULL );
	}
	return( -1 );
}
Exemple #19
0
/* Reads the manifest
 * Returns 1 if successful or -1 on error
 */
int libfwevt_manifest_read(
     libfwevt_manifest_t *manifest,
     const uint8_t *data,
     size_t data_size,
     libcerror_error_t **error )
{
	libfwevt_internal_manifest_t *internal_manifest = NULL;
	libfwevt_provider_t *provider                   = NULL;
	fwevt_template_manifest_t *wevt_manifest        = NULL;
	fwevt_template_provider_entry_t *provider_entry = NULL;
	static char *function                           = "libfwevt_manifest_read";
	size_t data_offset                              = 0;
	uint32_t number_of_providers                    = 0;
	uint32_t provider_data_offset                   = 0;
	uint32_t provider_index                         = 0;

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

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

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

		return( -1 );
	}
	internal_manifest = (libfwevt_internal_manifest_t *) manifest;

	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_size < sizeof( fwevt_template_manifest_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_manifest = (fwevt_template_manifest_t *) data;

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: manifest data:\n",
		 function );
		libcnotify_print_data(
		 (uint8_t *) wevt_manifest,
		 sizeof( fwevt_template_manifest_t ),
		 0 );
	}
#endif
	byte_stream_copy_to_uint16_little_endian(
	 wevt_manifest->major_version,
	 internal_manifest->major_version );

	byte_stream_copy_to_uint16_little_endian(
	 wevt_manifest->minor_version,
	 internal_manifest->minor_version );

	byte_stream_copy_to_uint32_little_endian(
	 wevt_manifest->number_of_providers,
	 number_of_providers );

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

		byte_stream_copy_to_uint32_little_endian(
		 wevt_manifest->size,
		 value_32bit );
		libcnotify_printf(
		 "%s: size\t\t\t\t\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

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

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

		libcnotify_printf(
		 "%s: number of providers\t\t\t\t: %" PRIu32 "\n",
		 function,
		 number_of_providers );

		libcnotify_printf(
		 "\n" );
	}
#endif
	if( memory_compare(
	     wevt_manifest->signature,
	     "CRIM",
	     4 ) != 0 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported manifest signature.",
		 function );

		goto on_error;
	}
	data_offset = sizeof( fwevt_template_manifest_t );

	if( libcdata_array_initialize(
	     &( internal_manifest->providers_array ),
	     number_of_providers,
	     error ) != 1 )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
		 "%s: unable to create providers array.",
		 function );

		goto on_error;
	}
	for( provider_index = 0;
	     provider_index < number_of_providers;
	     provider_index++ )
	{
		if( data_offset >= data_size )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: invalid data offset value out of bounds.",
			 function );

			goto on_error;
		}
		provider_entry = (fwevt_template_provider_entry_t *) &( data[ data_offset ] );

		if( ( data_offset + sizeof( fwevt_template_provider_entry_t ) ) >= data_size )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: invalid data value too small.",
			 function );

			goto on_error;
		}
		byte_stream_copy_to_uint32_little_endian(
		 provider_entry->data_offset,
		 provider_data_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 );

				goto on_error;
			}
			if( libfguid_identifier_copy_from_byte_stream(
			     guid,
			     provider_entry->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( 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: provider entry: %02" PRIu32 " identifier\t\t\t: %" PRIs_SYSTEM "\n",
			 function,
			 provider_index,
			 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;
			}
			libcnotify_printf(
			 "%s: provider entry: %02" PRIu32 " data offset\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 provider_index,
			 provider_data_offset );
		}
#endif
		data_offset += sizeof( fwevt_template_provider_entry_t );

		if( libfwevt_provider_initialize(
		     &provider,
		     provider_entry->identifier,
		     16,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
			 "%s: unable to create provider: %" PRIu32 ".",
			 function,
			 provider_index );

			goto on_error;
		}
		if( libfwevt_provider_read(
		     provider,
		     data,
		     data_size,
		     (size_t) provider_data_offset,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read provider: %d.",
			 function,
			 provider_index );

			goto on_error;
		}
		if( libcdata_array_set_entry_by_index(
		     internal_manifest->providers_array,
		     (int) provider_index,
		     (intptr_t *) provider,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
			 "%s: unable to set provider: %" PRIu32 ".",
			 function,
			 provider_index );

			goto on_error;
		}
		provider = NULL;
	}
/* TODO refactor to read on demand ? */
	for( provider_index = 0;
	     provider_index < number_of_providers;
	     provider_index++ )
	{
		if( libcdata_array_get_entry_by_index(
		     internal_manifest->providers_array,
		     provider_index,
		     (intptr_t **) &provider,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
			 "%s: unable to retrieve provider: %d.",
			 function,
			 provider_index );

			provider = NULL;

			goto on_error;
		}
		if( libfwevt_provider_read_channels(
		     provider,
		     data,
		     data_size,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read channels.",
			 function );

			provider = NULL;

			goto on_error;
		}
		if( libfwevt_provider_read_events(
		     provider,
		     data,
		     data_size,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read events.",
			 function );

			provider = NULL;

			goto on_error;
		}
		if( libfwevt_provider_read_keywords(
		     provider,
		     data,
		     data_size,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read keywords.",
			 function );

			provider = NULL;

			goto on_error;
		}
		if( libfwevt_provider_read_levels(
		     provider,
		     data,
		     data_size,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read levels.",
			 function );

			provider = NULL;

			goto on_error;
		}
		if( libfwevt_provider_read_maps(
		     provider,
		     data,
		     data_size,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read maps.",
			 function );

			provider = NULL;

			goto on_error;
		}
		if( libfwevt_provider_read_opcodes(
		     provider,
		     data,
		     data_size,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read opcodes.",
			 function );

			provider = NULL;

			goto on_error;
		}
		if( libfwevt_provider_read_tasks(
		     provider,
		     data,
		     data_size,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read tasks.",
			 function );

			provider = NULL;

			goto on_error;
		}
		if( libfwevt_provider_read_templates(
		     provider,
		     data,
		     data_size,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read templates.",
			 function );

			provider = NULL;

			goto on_error;
		}
	}
/* TODO end refactor */
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		if( number_of_providers > 0 )
		{
			libcnotify_printf(
			 "\n" );
		}
	}
#endif
	return( 1 );

on_error:
#if defined( HAVE_DEBUG_OUTPUT )
	if( guid != NULL )
	{
		libfguid_identifier_free(
		 &guid,
		 NULL );
	}
#endif
	if( provider != NULL )
	{
		libfwevt_provider_free(
		 &provider,
		 NULL );
	}
	if( internal_manifest->providers_array != NULL )
	{
		libcdata_array_free(
		 &( internal_manifest->providers_array ),
		 (int (*)(intptr_t **, libcerror_error_t **)) &libfwevt_provider_free,
		 NULL );
	}
	return( -1 );
}
/* Reads the event record values
 * Returns 1 if successful or -1 on error
 */
int libevt_record_values_read_event(
     libevt_record_values_t *record_values,
     uint8_t *record_data,
     size_t record_data_size,
     uint8_t strict_mode,
     libcerror_error_t **error )
{
	static char *function                 = "libevt_record_values_read_event";
	size_t record_data_offset             = 0;
	size_t strings_data_offset            = 0;
	ssize_t value_data_size               = 0;
	uint32_t data_offset                  = 0;
	uint32_t data_size                    = 0;
	uint32_t members_data_size            = 0;
	uint32_t size                         = 0;
	uint32_t size_copy                    = 0;
	uint32_t strings_offset               = 0;
	uint32_t strings_size                 = 0;
	uint32_t user_sid_offset              = 0;
	uint32_t user_sid_size                = 0;

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

	libfdatetime_posix_time_t *posix_time = NULL;
	uint32_t value_32bit                  = 0;
	uint16_t value_16bit                  = 0;
	int result                            = 0;
#endif

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

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

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

		return( -1 );
	}
	if( record_data_size < ( sizeof( evt_record_event_header_t ) + 4 ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
		 "%s: record data size value out of bounds.",
		 function );

		return( -1 );
	}
	byte_stream_copy_to_uint32_little_endian(
	 ( (evt_record_event_header_t *) record_data )->size,
	 size );

	byte_stream_copy_to_uint32_little_endian(
	 ( (evt_record_event_header_t *) record_data )->record_number,
	 record_values->number );

	byte_stream_copy_to_uint32_little_endian(
	 ( (evt_record_event_header_t *) record_data )->creation_time,
	 record_values->creation_time );

	byte_stream_copy_to_uint32_little_endian(
	 ( (evt_record_event_header_t *) record_data )->written_time,
	 record_values->written_time );

	byte_stream_copy_to_uint32_little_endian(
	 ( (evt_record_event_header_t *) record_data )->event_identifier,
	 record_values->event_identifier );

	byte_stream_copy_to_uint16_little_endian(
	 ( (evt_record_event_header_t *) record_data )->event_type,
	 record_values->event_type );

	byte_stream_copy_to_uint16_little_endian(
	 ( (evt_record_event_header_t *) record_data )->event_category,
	 record_values->event_category );

	byte_stream_copy_to_uint32_little_endian(
	 ( (evt_record_event_header_t *) record_data )->strings_offset,
	 strings_offset );

	byte_stream_copy_to_uint32_little_endian(
	 ( (evt_record_event_header_t *) record_data )->user_sid_size,
	 user_sid_size );

	byte_stream_copy_to_uint32_little_endian(
	 ( (evt_record_event_header_t *) record_data )->user_sid_offset,
	 user_sid_offset );

	byte_stream_copy_to_uint32_little_endian(
	 ( (evt_record_event_header_t *) record_data )->data_size,
	 data_size );

	byte_stream_copy_to_uint32_little_endian(
	 ( (evt_record_event_header_t *) record_data )->data_offset,
	 data_offset );

	byte_stream_copy_to_uint32_little_endian(
	 &( record_data[ record_data_size - 4 ] ),
	 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,
		 ( (evt_record_event_header_t *) record_data )->signature[ 0 ],
		 ( (evt_record_event_header_t *) record_data )->signature[ 1 ],
		 ( (evt_record_event_header_t *) record_data )->signature[ 2 ],
		 ( (evt_record_event_header_t *) record_data )->signature[ 3 ] );

		libcnotify_printf(
		 "%s: record number\t\t\t\t: %" PRIu32 "\n",
		 function,
		 record_values->number );

		if( libfdatetime_posix_time_initialize(
		     &posix_time,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
			 "%s: unable to create POSIX time.",
			 function );

			goto on_error;
		}
		if( libfdatetime_posix_time_copy_from_byte_stream(
		     posix_time,
		     ( (evt_record_event_header_t *) record_data )->creation_time,
		     4,
		     LIBFDATETIME_ENDIAN_LITTLE,
		     LIBFDATETIME_POSIX_TIME_VALUE_TYPE_SECONDS_32BIT_SIGNED,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
			 "%s: unable to copy POSIX time from byte stream.",
			 function );

			goto on_error;
		}
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
		result = libfdatetime_posix_time_copy_to_utf16_string(
			  posix_time,
			  (uint16_t *) posix_time_string,
			  32,
			  LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
			  error );
#else
		result = libfdatetime_posix_time_copy_to_utf8_string(
			  posix_time,
			  (uint8_t *) posix_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_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
			 "%s: unable to copy POSIX time to string.",
			 function );

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

		if( libfdatetime_posix_time_copy_from_byte_stream(
		     posix_time,
		     ( (evt_record_event_header_t *) record_data )->written_time,
		     4,
		     LIBFDATETIME_ENDIAN_LITTLE,
		     LIBFDATETIME_POSIX_TIME_VALUE_TYPE_SECONDS_32BIT_SIGNED,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
			 "%s: unable to copy POSIX time from byte stream.",
			 function );

			goto on_error;
		}
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
		result = libfdatetime_posix_time_copy_to_utf16_string(
			  posix_time,
			  (uint16_t *) posix_time_string,
			  32,
			  LIBFDATETIME_STRING_FORMAT_TYPE_CTIME | LIBFDATETIME_STRING_FORMAT_FLAG_DATE_TIME,
			  error );
#else
		result = libfdatetime_posix_time_copy_to_utf8_string(
			  posix_time,
			  (uint8_t *) posix_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_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
			 "%s: unable to copy POSIX time to string.",
			 function );

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

		if( libfdatetime_posix_time_free(
		     &posix_time,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
			 "%s: unable to free POSIX time.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "%s: event identifier\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 record_values->event_identifier );

		libcnotify_printf(
		 "%s: event identifier: code\t\t\t: %" PRIu32 "\n",
		 function,
		 record_values->event_identifier & 0x0000ffffUL );

		libcnotify_printf(
		 "%s: event identifier: facility\t\t: %" PRIu32 "\n",
		 function,
		 ( record_values->event_identifier & 0x0fff0000UL ) >> 16 );

		libcnotify_printf(
		 "%s: event identifier: reserved\t\t: %" PRIu32 "\n",
		 function,
		 ( record_values->event_identifier & 0x10000000UL ) >> 28 );

		libcnotify_printf(
		 "%s: event identifier: customer flags\t: %" PRIu32 "\n",
		 function,
		 ( record_values->event_identifier & 0x20000000UL ) >> 29 );

		libcnotify_printf(
		 "%s: event identifier: severity\t\t: %" PRIu32 " (",
		 function,
		 ( record_values->event_identifier & 0xc0000000UL ) >> 30 );
		libevt_debug_print_event_identifier_severity(
		 record_values->event_identifier );
		libcnotify_printf(
		 ")\n" );

		libcnotify_printf(
		 "%s: event type\t\t\t\t: %" PRIu16 " (",
		 function,
		 record_values->event_type );
		libevt_debug_print_event_type(
		 record_values->event_type );
		libcnotify_printf(
		 ")\n" );

		byte_stream_copy_to_uint16_little_endian(
		 ( (evt_record_event_header_t *) record_data )->number_of_strings,
		 value_16bit );
		libcnotify_printf(
		 "%s: number of strings\t\t\t: %" PRIu16 "\n",
		 function,
		 value_16bit );

		libcnotify_printf(
		 "%s: event category\t\t\t\t: %" PRIu16 "\n",
		 function,
		 record_values->event_category );

		byte_stream_copy_to_uint16_little_endian(
		 ( (evt_record_event_header_t *) record_data )->event_flags,
		 value_16bit );
		libcnotify_printf(
		 "%s: event flags\t\t\t\t: 0x%04" PRIx16 "\n",
		 function,
		 value_16bit );

		byte_stream_copy_to_uint32_little_endian(
		 ( (evt_record_event_header_t *) record_data )->closing_record_number,
		 value_32bit );
		libcnotify_printf(
		 "%s: closing record values number\t\t: %" PRIu32 "\n",
		 function,
		 value_32bit );

		libcnotify_printf(
		 "%s: strings offset\t\t\t\t: %" PRIu32 "\n",
		 function,
		 strings_offset );

		libcnotify_printf(
		 "%s: user security identifier (SID) size\t: %" PRIu32 "\n",
		 function,
		 user_sid_size );

		libcnotify_printf(
		 "%s: user security identifier (SID) offset\t: %" PRIu32 "\n",
		 function,
		 user_sid_offset );

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

		libcnotify_printf(
		 "%s: data offset\t\t\t\t: %" PRIu32 "\n",
		 function,
		 data_offset );
	}
/* Reads an index node
 * Returns 1 if successful or -1 on error
 */
int libpff_index_node_read(
     libpff_index_node_t *index_node,
     libpff_io_handle_t *io_handle,
     libbfio_handle_t *file_io_handle,
     off64_t node_offset,
     libcerror_error_t **error )
{
	uint8_t *index_node_footer_data              = NULL;
	static char *function                        = "libpff_index_node_read";
	ssize_t read_count                           = 0;
	uint32_t calculated_checksum                 = 0;
	uint32_t stored_checksum                     = 0;
	uint8_t calculated_entry_size                = 0;
	uint8_t calculated_maximum_number_of_entries = 0;
	uint8_t index_node_type_copy                 = 0;
	int result                                   = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	uint8_t *index_node_entry_data               = NULL;
	uint64_t value_64bit                         = 0;
	uint32_t value_32bit                         = 0;
	uint16_t entry_index                         = 0;
	uint16_t index_node_entry_data_size          = 0;
	uint16_t value_16bit                         = 0;
#endif

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

		return( -1 );
	}
	if( index_node->data != NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
		 "%s: invalid index node - data already set.",
		 function );

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

		return( -1 );
	}
	if( ( io_handle->file_type != LIBPFF_FILE_TYPE_32BIT )
	 && ( io_handle->file_type != LIBPFF_FILE_TYPE_64BIT )
	 && ( io_handle->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( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
	{
		index_node->data_size                 = 512;
		index_node->maximum_entries_data_size = 512 - sizeof( pff_index_node_32bit_footer_t );
	}
	else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
	{
		index_node->data_size                 = 512;
		index_node->maximum_entries_data_size = 512 - sizeof( pff_index_node_64bit_footer_t );
	}
	else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE )
	{
		index_node->data_size                 = 4096;
		index_node->maximum_entries_data_size = 4096 - sizeof( pff_index_node_64bit_4k_page_footer_t );
	}
	index_node->data = (uint8_t *) memory_allocate(
	                                sizeof( uint8_t ) * index_node->data_size );

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

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

		goto on_error;
	}
	read_count = libbfio_handle_read_buffer(
	              file_io_handle,
	              index_node->data,
	              index_node->data_size,
	              error );

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

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: index node data:\n",
		 function );
		libcnotify_print_data(
		 index_node->data,
		 index_node->data_size,
		 LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA );
	}
#endif
	index_node_footer_data = &( index_node->data[ index_node->maximum_entries_data_size ] );

	if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
	{
		index_node->type     = ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->type;
		index_node_type_copy = ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->type_copy;

		byte_stream_copy_to_uint32_little_endian(
		 ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->back_pointer,
		 index_node->back_pointer );
		byte_stream_copy_to_uint32_little_endian(
		 ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->checksum,
		 stored_checksum );

		index_node->number_of_entries         = ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->number_of_entries;
		index_node->maximum_number_of_entries = ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->maximum_number_of_entries;
		index_node->entry_size                = ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->entry_size;
		index_node->level                     = ( (pff_index_node_32bit_footer_t *) index_node_footer_data )->level;

		if( ( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR )
		 && ( index_node->level == LIBPFF_INDEX_NODE_LEVEL_LEAF ) )
		{
			calculated_entry_size                = 16;
			calculated_maximum_number_of_entries = 496 / 16;
		}
		else
		{
			calculated_entry_size                = 12;
			calculated_maximum_number_of_entries = 496 / 12;
		}
	}
	else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
	{
		index_node->type     = ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->type;
		index_node_type_copy = ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->type_copy;

		byte_stream_copy_to_uint32_little_endian(
		 ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->checksum,
		 stored_checksum );
		byte_stream_copy_to_uint64_little_endian(
		 ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->back_pointer,
		 index_node->back_pointer );

		index_node->number_of_entries         = ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->number_of_entries;
		index_node->maximum_number_of_entries = ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->maximum_number_of_entries;
		index_node->entry_size                = ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->entry_size;
		index_node->level                     = ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->level;

		if( ( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR )
		 && ( index_node->level == LIBPFF_INDEX_NODE_LEVEL_LEAF ) )
		{
			calculated_entry_size                = 32;
			calculated_maximum_number_of_entries = 488 / 32;
		}
		else
		{
			calculated_entry_size                = 24;
			calculated_maximum_number_of_entries = 488 / 24;
		}
	}
	else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE )
	{
		index_node->type     = ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->type;
		index_node_type_copy = ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->type_copy;

		byte_stream_copy_to_uint32_little_endian(
		 ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->checksum,
		 stored_checksum );
		byte_stream_copy_to_uint64_little_endian(
		 ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->back_pointer,
		 index_node->back_pointer );

		byte_stream_copy_to_uint16_little_endian(
		 ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->number_of_entries,
		 index_node->number_of_entries );
		byte_stream_copy_to_uint16_little_endian(
		 ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->maximum_number_of_entries,
		 index_node->maximum_number_of_entries );

		index_node->entry_size = ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->entry_size;
		index_node->level      = ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->level;

		if( ( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR )
		 && ( index_node->level == LIBPFF_INDEX_NODE_LEVEL_LEAF ) )
		{
			calculated_entry_size                = 32;
			calculated_maximum_number_of_entries = 4056 / 32;
		}
		else
		{
			calculated_entry_size                = 24;
			calculated_maximum_number_of_entries = 4056 / 24;
		}
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: number of entries\t\t\t\t: %" PRIu16 "\n",
		 function,
		 index_node->number_of_entries );

		libcnotify_printf(
		 "%s: maximum number of entries\t\t\t: %" PRIu16 "\n",
		 function,
		 index_node->maximum_number_of_entries );

		libcnotify_printf(
		 "%s: entry size\t\t\t\t\t: %" PRIu8 "\n",
		 function,
		 index_node->entry_size );

		libcnotify_printf(
		 "%s: node level\t\t\t\t\t: %" PRIu8 "\n",
		 function,
		 index_node->level );

		if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
		{
			libcnotify_printf(
			 "%s: padding:\n",
			 function );
			libcnotify_print_data(
			 ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->padding1,
			 4,
			 0 );
		}
		else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE )
		{
			libcnotify_printf(
			 "%s: padding:\n",
			 function );
			libcnotify_print_data(
			 ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->padding1,
			 10,
			 0 );
		}
		libcnotify_printf(
		 "%s: index node type\t\t\t\t\t: 0x%02" PRIx8 "\n",
		 function,
		 index_node->type );
		libcnotify_printf(
		 "%s: index node type copy\t\t\t\t: 0x%02" PRIx8 "\n",
		 function,
		 index_node_type_copy );

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

			libcnotify_printf(
			 "%s: back pointer\t\t\t\t\t: 0x%08" PRIx64 "\n",
			 function,
			 index_node->back_pointer );
			libcnotify_printf(
			 "%s: checksum\t\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 stored_checksum );
		}
		else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
		{
			byte_stream_copy_to_uint16_little_endian(
			 ( (pff_index_node_64bit_footer_t *) index_node_footer_data )->signature,
			 value_16bit );
			libcnotify_printf(
			 "%s: signature\t\t\t\t\t: 0x%04" PRIx16 "\n",
			 function,
			 value_16bit );

			libcnotify_printf(
			 "%s: checksum\t\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 stored_checksum );
			libcnotify_printf(
			 "%s: back pointer\t\t\t\t\t: 0x%08" PRIx64 "\n",
			 function,
			 index_node->back_pointer );
		}
		else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE )
		{
			byte_stream_copy_to_uint16_little_endian(
			 ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->signature,
			 value_16bit );
			libcnotify_printf(
			 "%s: signature\t\t\t\t\t: 0x%04" PRIx16 "\n",
			 function,
			 value_16bit );

			libcnotify_printf(
			 "%s: checksum\t\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 stored_checksum );
			libcnotify_printf(
			 "%s: back pointer\t\t\t\t\t: 0x%08" PRIx64 "\n",
			 function,
			 index_node->back_pointer );

			byte_stream_copy_to_uint64_little_endian(
			 ( (pff_index_node_64bit_4k_page_footer_t *) index_node_footer_data )->unknown1,
			 value_64bit );
			libcnotify_printf(
			 "%s: unknown1\t\t\t\t\t: 0x%08" PRIx64 "\n",
			 function,
			 value_64bit );
		}
		libcnotify_printf(
		 "\n" );
	}
#endif

	if( index_node->type != index_node_type_copy )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: mismatch in index node type (0x%02" PRIx8 " != 0x%02" PRIx8 ").\n",
			 function,
			 index_node->type,
			 index_node_type_copy );
		}
#endif
		if( ( index_node->type != LIBPFF_INDEX_TYPE_DESCRIPTOR )
		 && ( index_node->type != LIBPFF_INDEX_TYPE_OFFSET )
		 && ( ( index_node_type_copy == LIBPFF_INDEX_TYPE_DESCRIPTOR )
		   || ( index_node_type_copy == LIBPFF_INDEX_TYPE_OFFSET ) ) )
		{
			index_node->type = index_node_type_copy;
		}
	}
	if( ( index_node->type != LIBPFF_INDEX_TYPE_DESCRIPTOR )
	 && ( index_node->type != LIBPFF_INDEX_TYPE_OFFSET ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported index node type: 0x%02" PRIx8 ".",
		 function,
		 index_node->type );

		goto on_error;
	}
	if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
	{
		result = libfmapi_checksum_calculate_weak_crc32(
		          &calculated_checksum,
		          index_node->data,
		          500,
		          0,
		          error );
	}
	else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
	{
		result = libfmapi_checksum_calculate_weak_crc32(
		          &calculated_checksum,
		          index_node->data,
		          496,
		          0,
		          error );
	}
	else if( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE )
	{
		result = libfmapi_checksum_calculate_weak_crc32(
		          &calculated_checksum,
		          index_node->data,
		          4072,
		          0,
		          error );
	}
	if( result != 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 )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: mismatch in checksum ( 0x%08" PRIx32 " != 0x%08" PRIx32 " ).\n",
			 function,
			 stored_checksum,
			 calculated_checksum );
		}
#endif
		/* TODO smart error handling */
	}
	if( ( index_node->entry_size != 0 )
	 && ( index_node->entry_size != calculated_entry_size ) )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: entry size mismatch (calculated: %" PRIu8 ", stored: %" PRIu8 ").\n",
			 function,
			 calculated_entry_size,
			 index_node->entry_size );
		}
#endif
		index_node->entry_size = calculated_entry_size;
	}
	if( ( index_node->maximum_number_of_entries != 0 )
	 && ( index_node->maximum_number_of_entries != calculated_maximum_number_of_entries ) )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: maximum number of entries mismatch (calculated: %" PRIu8 ", stored: %" PRIu8 ").\n",
			 function,
			 calculated_maximum_number_of_entries,
			 index_node->maximum_number_of_entries );
		}
#endif
		index_node->maximum_number_of_entries = calculated_maximum_number_of_entries;
	}
	if( index_node->number_of_entries > index_node->maximum_number_of_entries )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: number of entries: %" PRIu8 ", exceeds maximum: %" PRIu8 ".",
			 function,
			 index_node->number_of_entries,
			 index_node->maximum_number_of_entries );
		}
#endif
		index_node->number_of_entries = index_node->maximum_number_of_entries;
	}
	if( ( (uint16_t) index_node->number_of_entries * (uint16_t) index_node->entry_size ) > index_node->maximum_entries_data_size )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
		 "%s: size of entries: %" PRIu16 ", exceeds maximum: %" PRIu16 ".",
		 function,
		 index_node->number_of_entries * index_node->entry_size,
		 index_node->maximum_entries_data_size );

		goto on_error;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		index_node_entry_data      = index_node->data;
		index_node_entry_data_size = index_node->maximum_entries_data_size;

		/* Print all the entries
		 */
		for( entry_index = 0;
		     entry_index < index_node->maximum_number_of_entries;
		     entry_index++ )
		{
			if( entry_index == index_node->number_of_entries )
			{
				result = libpff_index_node_check_for_empty_block(
					  index_node_entry_data,
					  index_node_entry_data_size,
					  error );

				if( result == -1 )
				{
					libcerror_error_set(
					 error,
					 LIBCERROR_ERROR_DOMAIN_RUNTIME,
					 LIBCERROR_RUNTIME_ERROR_GET_FAILED,
					 "%s: unable to determine if remaining index nodes are empty.",
					 function );

					return( -1 );
				}
				else if( result != 0 )
				{
					break;
				}
				libcnotify_printf(
				 "\n" );
				libcnotify_printf(
				 "%s: remaining node entries\n",
				 function );
			}
			if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
			{
				byte_stream_copy_to_uint32_little_endian(
				 index_node_entry_data,
				 value_64bit );
			}
			else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
			      || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
			{
				byte_stream_copy_to_uint64_little_endian(
				 index_node_entry_data,
				 value_64bit );
			}
			libcnotify_printf(
			 "%s: entry: %03" PRIu16 " index node identifier\t\t: 0x%08" PRIx64 " (%" PRIu64 ")\n",
			 function,
			 entry_index,
			 value_64bit,
			 value_64bit );

			/* Process descriptor index node leaf nodes
			 */
			if( ( index_node->type == LIBPFF_INDEX_TYPE_DESCRIPTOR )
			 && ( index_node->level == LIBPFF_INDEX_NODE_LEVEL_LEAF ) )
			{
				if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
				{
					byte_stream_copy_to_uint32_little_endian(
					 ( (pff_index_node_descriptor_entry_32bit_t *) index_node_entry_data )->data_identifier,
					 value_64bit );
				}
				else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
				      || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
				{
					byte_stream_copy_to_uint64_little_endian(
					 ( (pff_index_node_descriptor_entry_64bit_t *) index_node_entry_data )->data_identifier,
					 value_64bit );
				}
				libcnotify_printf(
				 "%s: entry: %03" PRIu16 " data identifier\t\t\t: 0x%08" PRIx64 " (%" PRIu64 ")\n",
				 function,
				 entry_index,
				 value_64bit,
				 value_64bit );

				if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
				{
					byte_stream_copy_to_uint32_little_endian(
					 ( (pff_index_node_descriptor_entry_32bit_t *) index_node_entry_data )->local_descriptors_identifier,
					 value_64bit );
				}
				else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
				      || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
				{
					byte_stream_copy_to_uint64_little_endian(
					 ( (pff_index_node_descriptor_entry_64bit_t *) index_node_entry_data )->local_descriptors_identifier,
					 value_64bit );
				}
				libcnotify_printf(
				 "%s: entry: %03" PRIu16 " local descriptors identifier\t\t: 0x%08" PRIx64 " (%" PRIu64 ")\n",
				 function,
				 entry_index,
				 value_64bit,
				 value_64bit );

				if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
				{
					byte_stream_copy_to_uint32_little_endian(
					 ( (pff_index_node_descriptor_entry_32bit_t *) index_node_entry_data )->parent_identifier,
					 value_32bit );
				}
				else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
				      || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
				{
					byte_stream_copy_to_uint32_little_endian(
					 ( (pff_index_node_descriptor_entry_64bit_t *) index_node_entry_data )->parent_identifier,
					 value_32bit );
				}
				libcnotify_printf(
				 "%s: entry: %03" PRIu16 " parent identifier\t\t\t: 0x%08" PRIx32 " (%" PRIu32 ")\n",
				 function,
				 entry_index,
				 value_32bit,
				 value_32bit );

				if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
				 || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
				{
					byte_stream_copy_to_uint32_little_endian(
					 ( (pff_index_node_descriptor_entry_64bit_t *) index_node_entry_data )->unknown1,
					 value_32bit );

					libcnotify_printf(
					 "%s: entry: %03" PRIu16 " unknown1\t\t\t\t: 0x%08" PRIx32 " (%" PRIu32 ")\n",
					 function,
					 entry_index,
					 value_32bit,
					 value_32bit );
				}
			}
			/* Process offset and descriptor index node branch nodes and offset index node leaf nodes
			 */
			else
			{
				if( index_node->level != LIBPFF_INDEX_NODE_LEVEL_LEAF )
				{
					if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
					{
						byte_stream_copy_to_uint32_little_endian(
						 ( (pff_index_node_branch_entry_32bit_t *) index_node_entry_data )->back_pointer,
						 value_64bit );
					}
					else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
					      || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
					{
						byte_stream_copy_to_uint64_little_endian(
						 ( (pff_index_node_branch_entry_64bit_t *) index_node_entry_data )->back_pointer,
						 value_64bit );
					}
					libcnotify_printf(
					 "%s: entry: %03" PRIu16 " back pointer\t\t\t\t: 0x%08" PRIx64 "\n",
					 function,
					 entry_index,
					 value_64bit );
				}
				if( index_node->level == LIBPFF_INDEX_NODE_LEVEL_LEAF )
				{
					if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
					{
						byte_stream_copy_to_uint32_little_endian(
						 ( (pff_index_node_offset_entry_32bit_t *) index_node_entry_data )->file_offset,
						 value_64bit );
					}
					else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
					      || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
					{
						byte_stream_copy_to_uint64_little_endian(
						 ( (pff_index_node_offset_entry_64bit_t *) index_node_entry_data )->file_offset,
						 value_64bit );
					}
				}
				else
				{
					if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
					{
						byte_stream_copy_to_uint32_little_endian(
						 ( (pff_index_node_branch_entry_32bit_t *) index_node_entry_data )->file_offset,
						 value_64bit );
					}
					else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
					      || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
					{
						byte_stream_copy_to_uint64_little_endian(
						 ( (pff_index_node_branch_entry_64bit_t *) index_node_entry_data )->file_offset,
						 value_64bit );
					}
				}
				libcnotify_printf(
				 "%s: entry: %03" PRIu16 " file offset\t\t\t\t: 0x%08" PRIx64 " (%" PRIu64 ")\n",
				 function,
				 entry_index,
				 value_64bit,
				 value_64bit );

				if( index_node->level == LIBPFF_INDEX_NODE_LEVEL_LEAF )
				{
					if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
					{
						byte_stream_copy_to_uint16_little_endian(
						 ( (pff_index_node_offset_entry_32bit_t *) index_node_entry_data )->data_size,
						 value_16bit );
					}
					else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
					      || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
					{
						byte_stream_copy_to_uint16_little_endian(
						 ( (pff_index_node_offset_entry_64bit_t *) index_node_entry_data )->data_size,
						 value_16bit );
					}
					libcnotify_printf(
					 "%s: entry: %03" PRIu16 " data size\t\t\t\t: %" PRIu16 "\n",
					 function,
					 entry_index,
					 value_16bit );

					if( io_handle->file_type == LIBPFF_FILE_TYPE_32BIT )
					{
						byte_stream_copy_to_uint16_little_endian(
						 ( (pff_index_node_offset_entry_32bit_t *) index_node_entry_data )->reference_count,
						 value_16bit );
					}
					else if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
					      || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
					{
						byte_stream_copy_to_uint16_little_endian(
						 ( (pff_index_node_offset_entry_64bit_t *) index_node_entry_data )->reference_count,
						 value_16bit );
					}
					libcnotify_printf(
					 "%s: entry: %03" PRIu16 " reference count\t\t\t: %" PRIu16 "\n",
					 function,
					 entry_index,
					 value_16bit );

					if( ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT )
					 || ( io_handle->file_type == LIBPFF_FILE_TYPE_64BIT_4K_PAGE ) )
					{
						byte_stream_copy_to_uint32_little_endian(
						 ( (pff_index_node_offset_entry_64bit_t *) index_node_entry_data )->data_allocation_table_file_offset,
						 value_32bit );

						libcnotify_printf(
						 "%s: entry: %03" PRIu16 " data allocation table offset\t\t: 0x%08" PRIx32 " (%" PRIu32 ")\n",
						 function,
						 entry_index,
						 value_32bit,
						 value_32bit );
					}
				}
			}
			index_node_entry_data      += index_node->entry_size;
			index_node_entry_data_size -= index_node->entry_size;
		}
		libcnotify_printf(
		 "\n" );
	}
#endif
	index_node->entries_data = index_node->data;

	return( 1 );

on_error:
	if( index_node->data != NULL )
	{
		memory_free(
		 index_node->data );

		index_node->data = NULL;
	}
	return( -1 );
}
/* Reads the reparse point values
 * Returns 1 if successful or -1 on error
 */
int libfsntfs_reparse_point_values_read_data(
     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_data";
	uint32_t flags                   = 0;

#if defined( HAVE_DEBUG_OUTPUT )
	system_character_t *value_string = NULL;
	size_t value_string_size         = 0;
	int result                       = 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
	byte_stream_copy_to_uint32_little_endian(
	 ( (fsntfs_reparse_point_t *) data )->tag,
	 reparse_point_values->tag );

	byte_stream_copy_to_uint16_little_endian(
	 ( (fsntfs_reparse_point_t *) data )->reparse_data_size,
	 reparse_point_values->reparse_data_size );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: tag\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 reparse_point_values->tag );
		libfsntfs_debug_print_reparse_point_tag(
		 reparse_point_values->tag );
		libcnotify_printf(
		 "\n" );

		libcnotify_printf(
		 "%s: reparse data size\t\t: %" PRIu16 "\n",
		 function,
		 reparse_point_values->reparse_data_size );

		libcnotify_printf(
		 "\n" );
	}
#endif
	if( reparse_point_values->reparse_data_size > 0 )
	{
		if( ( sizeof( fsntfs_reparse_point_t ) > data_size )
		 || ( (size_t) reparse_point_values->reparse_data_size > ( data_size - sizeof( fsntfs_reparse_point_t ) ) ) )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: invalid reparse data size value out of bounds.",
			 function );

			goto on_error;
		}
		reparse_point_values->reparse_data = (uint8_t *) memory_allocate(
		                                                  sizeof( uint8_t ) * reparse_point_values->reparse_data_size );

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

			goto on_error;
		}
		if( memory_copy(
		     reparse_point_values->reparse_data,
		     &( data[ sizeof( fsntfs_reparse_point_t ) ] ),
		     (size_t) reparse_point_values->reparse_data_size ) == NULL )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_MEMORY,
			 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
			 "%s: unable to copy reparse data.",
			 function );

			goto on_error;
		}
	}
	if( ( reparse_point_values->tag == 0xa0000003 )
	 || ( reparse_point_values->tag == 0xa000000c ) )
	{
		byte_stream_copy_to_uint16_little_endian(
		 ( (fsntfs_mount_point_reparse_data_t *) reparse_point_values->reparse_data )->substitute_name_offset,
		 reparse_point_values->substitute_name_offset );

		byte_stream_copy_to_uint16_little_endian(
		 ( (fsntfs_mount_point_reparse_data_t *) reparse_point_values->reparse_data )->substitute_name_size,
		 reparse_point_values->substitute_name_size );

		byte_stream_copy_to_uint16_little_endian(
		 ( (fsntfs_mount_point_reparse_data_t *) reparse_point_values->reparse_data )->print_name_offset,
		 reparse_point_values->print_name_offset );

		byte_stream_copy_to_uint16_little_endian(
		 ( (fsntfs_mount_point_reparse_data_t *) reparse_point_values->reparse_data )->print_name_size,
		 reparse_point_values->print_name_size );

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: substitute name offset\t: 0x%04" PRIx16 "\n",
			 function,
			 reparse_point_values->substitute_name_offset );

			libcnotify_printf(
			 "%s: substitute name size\t\t: %" PRIu16 "\n",
			 function,
			 reparse_point_values->substitute_name_size );

			libcnotify_printf(
			 "%s: print name offset\t\t: 0x%04" PRIx16 "\n",
			 function,
			 reparse_point_values->print_name_offset );

			libcnotify_printf(
			 "%s: print name size\t\t: %" PRIu16 "\n",
			 function,
			 reparse_point_values->print_name_size );
		}
#endif
	}
	if( reparse_point_values->tag == 0xa0000003 )
	{
		reparse_point_values->substitute_name_offset += sizeof( fsntfs_mount_point_reparse_data_t );
		reparse_point_values->print_name_offset      += sizeof( fsntfs_mount_point_reparse_data_t );
	}
	else if( reparse_point_values->tag == 0xa000000c )
	{
		byte_stream_copy_to_uint32_little_endian(
		 ( (fsntfs_symbolic_link_reparse_data_t *) reparse_point_values->reparse_data )->flags,
		 flags );

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: flags\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 flags );
		}
#endif
		reparse_point_values->substitute_name_offset += sizeof( fsntfs_symbolic_link_reparse_data_t );
		reparse_point_values->print_name_offset      += sizeof( fsntfs_symbolic_link_reparse_data_t );
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		if( ( reparse_point_values->tag == 0xa0000003 )
		 || ( reparse_point_values->tag == 0xa000000c ) )
		{
			libcnotify_printf(
			 "\n" );
		}
		else
		{
			libcnotify_printf(
			 "%s: unusupported reparse point tag: 0x%08" PRIx32 "\n",
			 function,
			 reparse_point_values->tag );
		}
	}
#endif
	if( reparse_point_values->substitute_name_size > 0 )
	{
		if( reparse_point_values->substitute_name_offset >= reparse_point_values->reparse_data_size )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: invalid substitute name offset value out of bounds.",
			 function );

			goto on_error;
		}
		if( reparse_point_values->substitute_name_size > ( reparse_point_values->reparse_data_size - reparse_point_values->substitute_name_offset ) )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: invalid substitute name size value out of bounds.",
			 function );

			goto on_error;
		}
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
			result = libuna_utf16_string_size_from_utf16_stream(
				  &( reparse_point_values->reparse_data[ reparse_point_values->substitute_name_offset ] ),
				  (size_t) reparse_point_values->substitute_name_size,
				  LIBUNA_ENDIAN_LITTLE,
				  &value_string_size,
				  error );
#else
			result = libuna_utf8_string_size_from_utf16_stream(
				  &( reparse_point_values->reparse_data[ reparse_point_values->substitute_name_offset ] ),
				  (size_t) reparse_point_values->substitute_name_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 substitute name string.",
				 function );

				goto on_error;
			}
			value_string = 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 substitute name string.",
				 function );

				goto on_error;
			}
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
			result = libuna_utf16_string_copy_from_utf16_stream(
				  (libuna_utf16_character_t *) value_string,
				  value_string_size,
				  &( reparse_point_values->reparse_data[ reparse_point_values->substitute_name_offset ] ),
				  (size_t) reparse_point_values->substitute_name_size,
				  LIBUNA_ENDIAN_LITTLE,
				  error );
#else
			result = libuna_utf8_string_copy_from_utf16_stream(
				  (libuna_utf8_character_t *) value_string,
				  value_string_size,
				  &( reparse_point_values->reparse_data[ reparse_point_values->substitute_name_offset ] ),
				  (size_t) reparse_point_values->substitute_name_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 substitute name string.",
				 function );

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

			memory_free(
			 value_string );

			value_string = NULL;
		}
#endif
	}
	if( reparse_point_values->print_name_size > 0 )
	{
		if( reparse_point_values->print_name_offset >= reparse_point_values->reparse_data_size )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: invalid print name offset value out of bounds.",
			 function );

			goto on_error;
		}
		if( reparse_point_values->print_name_size > ( reparse_point_values->reparse_data_size - reparse_point_values->print_name_offset ) )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
			 "%s: invalid print name size value out of bounds.",
			 function );

			goto on_error;
		}
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
			result = libuna_utf16_string_size_from_utf16_stream(
				  &( reparse_point_values->reparse_data[ reparse_point_values->print_name_offset ] ),
				  (size_t) reparse_point_values->print_name_size,
				  LIBUNA_ENDIAN_LITTLE,
				  &value_string_size,
				  error );
#else
			result = libuna_utf8_string_size_from_utf16_stream(
				  &( reparse_point_values->reparse_data[ reparse_point_values->print_name_offset ] ),
				  (size_t) reparse_point_values->print_name_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 print name string.",
				 function );

				goto on_error;
			}
			value_string = 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 print name string.",
				 function );

				goto on_error;
			}
#if defined( HAVE_WIDE_SYSTEM_CHARACTER )
			result = libuna_utf16_string_copy_from_utf16_stream(
				  (libuna_utf16_character_t *) value_string,
				  value_string_size,
				  &( reparse_point_values->reparse_data[ reparse_point_values->print_name_offset ] ),
				  (size_t) reparse_point_values->print_name_size,
				  LIBUNA_ENDIAN_LITTLE,
				  error );
#else
			result = libuna_utf8_string_copy_from_utf16_stream(
				  (libuna_utf8_character_t *) value_string,
				  value_string_size,
				  &( reparse_point_values->reparse_data[ reparse_point_values->print_name_offset ] ),
				  (size_t) reparse_point_values->print_name_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 print name string.",
				 function );

				goto on_error;
			}
			libcnotify_printf(
			 "%s: print name\t\t\t: %" PRIs_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
	if( reparse_point_values->reparse_data != NULL )
	{
		memory_free(
		 reparse_point_values->reparse_data );

		reparse_point_values->reparse_data = NULL;
	}
	reparse_point_values->reparse_data_size = 0;

	return( -1 );
}
/* Reads the compressed folder values
 * Returns the number of bytes read if successful, 0 if not able to read or -1 on error
 */
ssize_t libfwsi_compressed_folder_values_read(
         libfwsi_compressed_folder_values_t *compressed_folder_values,
         const uint8_t *shell_item_data,
         size_t shell_item_data_size,
         libcerror_error_t **error )
{
	static char *function                       = "libfwsi_compressed_folder_values_read";
	size_t shell_item_data_offset               = 0;
	uint32_t string_size                        = 0;

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

	libcstring_system_character_t *value_string = NULL;
	libfdatetime_fat_date_time_t *fat_date_time = NULL;
	size_t value_string_size                    = 0;
	uint64_t value_64bit                        = 0;
	uint32_t value_32bit                        = 0;
	uint16_t value_16bit                        = 0;
	int result                                  = 0;
#endif

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

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

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

		return( -1 );
	}
	/* Do not try to parse unsupported shell item data sizes
	 */
	if( shell_item_data_size < 6 )
	{
		return( 0 );
	}
	/* Do not try to parse unknown class type indicators
	 */
	if( shell_item_data[ 2 ] != 0x52 )
	{
		return( 0 );
	}
/* TODO: other variants not supported yet */
	if( ( shell_item_data[ 3 ] != 0x67 )
	 || ( shell_item_data[ 4 ] != 0xb1 )
	 || ( shell_item_data[ 5 ] != 0xac ) )
	{
		return( 0 );
	}
	if( ( shell_item_data[ 3 ] == 0x67 )
	 && ( shell_item_data[ 4 ] == 0xb1 )
	 && ( shell_item_data[ 5 ] == 0xac ) )
	{
		if( shell_item_data_size < 50 )
		{
			return( 0 );
		}
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: unknown1\t\t\t\t: 0x%02" PRIx8 "\n",
			 function,
			 shell_item_data[ 3 ] );

			byte_stream_copy_to_uint16_little_endian(
			 &( shell_item_data[ 4 ] ),
			 value_16bit );
			libcnotify_printf(
			 "%s: unknown2\t\t\t\t: 0x%04" PRIx16 "\n",
			 function,
			 value_16bit );

			byte_stream_copy_to_uint32_little_endian(
			 &( shell_item_data[ 6 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: unknown3\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			byte_stream_copy_to_uint64_little_endian(
			 &( shell_item_data[ 10 ] ),
			 value_64bit );
			libcnotify_printf(
			 "%s: unknown4\t\t\t\t: 0x%08" PRIx64 "\n",
			 function,
			 value_64bit );

			byte_stream_copy_to_uint32_little_endian(
			 &( shell_item_data[ 18 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: unknown5\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			byte_stream_copy_to_uint32_little_endian(
			 &( shell_item_data[ 22 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: unknown6\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			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_fat_date_time_copy_from_byte_stream(
			     fat_date_time,
			     &( shell_item_data[ 26 ] ),
			     4,
			     LIBFDATETIME_ENDIAN_LITTLE,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
				 "%s: unable to copy byte stream to FAT date time.",
				 function );

				goto on_error;
			}
#if defined( LIBCSTRING_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_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
				 "%s: unable to copy FAT date time to string.",
				 function );

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

			byte_stream_copy_to_uint32_little_endian(
			 &( shell_item_data[ 30 ] ),
			 value_32bit );
			libcnotify_printf(
			 "%s: unknown7\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 value_32bit );

			if( libfdatetime_fat_date_time_copy_from_byte_stream(
			     fat_date_time,
			     &( shell_item_data[ 34 ] ),
			     4,
			     LIBFDATETIME_ENDIAN_LITTLE,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
				 "%s: unable to copy byte stream to FAT date time.",
				 function );

				goto on_error;
			}
#if defined( LIBCSTRING_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_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_COPY_FAILED,
				 "%s: unable to copy FAT date time to string.",
				 function );

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

			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;
			}
			byte_stream_copy_to_uint64_little_endian(
			 &( shell_item_data[ 38 ] ),
			 value_64bit );
			libcnotify_printf(
			 "%s: unknown8\t\t\t\t: 0x%08" PRIx64 "\n",
			 function,
			 value_64bit );
		}
#endif
		shell_item_data_offset = 46;
	}
	byte_stream_copy_to_uint32_little_endian(
	 &( shell_item_data[ shell_item_data_offset ] ),
	 string_size );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: string size\t\t\t: %" PRIu32 "\n",
		 function,
		 string_size );
	}
#endif
	shell_item_data_offset += 4;

	string_size *= 2;

	if( ( string_size > 0 )
         && ( string_size <= shell_item_data_size )
	 && ( shell_item_data_offset <= ( shell_item_data_size - string_size ) ) )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
			result = libuna_utf16_string_size_from_utf16_stream(
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_size,
				  LIBUNA_ENDIAN_LITTLE,
				  &value_string_size,
				  error );
#else
			result = libuna_utf8_string_size_from_utf16_stream(
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_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 value string.",
				 function );

				goto on_error;
			}
			if( value_string_size > (size_t) ( SSIZE_MAX / sizeof( libcstring_system_character_t ) ) )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
				 "%s: invalid value 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 value 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,
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_size,
				  LIBUNA_ENDIAN_LITTLE,
				  error );
#else
			result = libuna_utf8_string_copy_from_utf16_stream(
				  (libuna_utf8_character_t *) value_string,
				  value_string_size,
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_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 value string.",
				 function );

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

			memory_free(
			 value_string );

			value_string = NULL;
		}
#endif
		shell_item_data_offset += string_size;
	}
	byte_stream_copy_to_uint32_little_endian(
	 &( shell_item_data[ shell_item_data_offset ] ),
	 string_size );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: string size\t\t\t: %" PRIu32 "\n",
		 function,
		 string_size );
	}
#endif
	shell_item_data_offset += 4;

	string_size *= 2;

	if( ( string_size > 0 )
         && ( string_size <= shell_item_data_size )
	 && ( shell_item_data_offset <= ( shell_item_data_size - string_size ) ) )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
			result = libuna_utf16_string_size_from_utf16_stream(
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_size,
				  LIBUNA_ENDIAN_LITTLE,
				  &value_string_size,
				  error );
#else
			result = libuna_utf8_string_size_from_utf16_stream(
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_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 value string.",
				 function );

				goto on_error;
			}
			if( value_string_size > (size_t) ( SSIZE_MAX / sizeof( libcstring_system_character_t ) ) )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
				 "%s: invalid value 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 value 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,
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_size,
				  LIBUNA_ENDIAN_LITTLE,
				  error );
#else
			result = libuna_utf8_string_copy_from_utf16_stream(
				  (libuna_utf8_character_t *) value_string,
				  value_string_size,
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_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 value string.",
				 function );

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

			memory_free(
			 value_string );

			value_string = NULL;
		}
#endif
		shell_item_data_offset += string_size;
	}
	byte_stream_copy_to_uint32_little_endian(
	 &( shell_item_data[ shell_item_data_offset ] ),
	 string_size );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: string size\t\t\t: %" PRIu32 "\n",
		 function,
		 string_size );
	}
#endif
	shell_item_data_offset += 4;

	string_size *= 2;

	if( ( string_size > 0 )
         && ( string_size <= shell_item_data_size )
	 && ( shell_item_data_offset <= ( shell_item_data_size - string_size ) ) )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
			result = libuna_utf16_string_size_from_utf16_stream(
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_size,
				  LIBUNA_ENDIAN_LITTLE,
				  &value_string_size,
				  error );
#else
			result = libuna_utf8_string_size_from_utf16_stream(
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_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 value string.",
				 function );

				goto on_error;
			}
			if( value_string_size > (size_t) ( SSIZE_MAX / sizeof( libcstring_system_character_t ) ) )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
				 "%s: invalid value 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 value 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,
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_size,
				  LIBUNA_ENDIAN_LITTLE,
				  error );
#else
			result = libuna_utf8_string_copy_from_utf16_stream(
				  (libuna_utf8_character_t *) value_string,
				  value_string_size,
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_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 value string.",
				 function );

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

			memory_free(
			 value_string );

			value_string = NULL;
		}
#endif
		shell_item_data_offset += string_size;
	}
	byte_stream_copy_to_uint32_little_endian(
	 &( shell_item_data[ shell_item_data_offset ] ),
	 string_size );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: string size\t\t\t: %" PRIu32 "\n",
		 function,
		 string_size );
	}
#endif
	shell_item_data_offset += 4;

	string_size *= 2;

	if( ( string_size > 0 )
         && ( string_size <= shell_item_data_size )
	 && ( shell_item_data_offset <= ( shell_item_data_size - string_size ) ) )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
			result = libuna_utf16_string_size_from_utf16_stream(
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_size,
				  LIBUNA_ENDIAN_LITTLE,
				  &value_string_size,
				  error );
#else
			result = libuna_utf8_string_size_from_utf16_stream(
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_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 value string.",
				 function );

				goto on_error;
			}
			if( value_string_size > (size_t) ( SSIZE_MAX / sizeof( libcstring_system_character_t ) ) )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
				 "%s: invalid value 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 value 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,
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_size,
				  LIBUNA_ENDIAN_LITTLE,
				  error );
#else
			result = libuna_utf8_string_copy_from_utf16_stream(
				  (libuna_utf8_character_t *) value_string,
				  value_string_size,
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_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 value string.",
				 function );

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

			memory_free(
			 value_string );

			value_string = NULL;
		}
#endif
		shell_item_data_offset += string_size;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "\n" );
	}
#endif
	return( (ssize_t) shell_item_data_offset );

on_error:
#if defined( HAVE_DEBUG_OUTPUT )
	if( value_string != NULL )
	{
		memory_free(
		 value_string );
	}
	if( fat_date_time != NULL )
	{
		libfdatetime_fat_date_time_free(
		 &fat_date_time,
		 NULL );
	}
#endif
	return( -1 );
}
/* Reads the control panel CPL file values
 * Returns the number of bytes read if successful, 0 if not able to read or -1 on error
 */
ssize_t libfwsi_control_panel_cpl_file_values_read(
         libfwsi_control_panel_cpl_file_values_t *control_panel_cpl_file_values,
         const uint8_t *shell_item_data,
         size_t shell_item_data_size,
         libcerror_error_t **error )
{
	static char *function                       = "libfwsi_control_panel_cpl_file_values_read";
	size_t shell_item_data_offset               = 0;
	size_t string_size                          = 0;
	uint32_t signature                          = 0;

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

	if( control_panel_cpl_file_values == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid control panel CPL file values.",
		 function );

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

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

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

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

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

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

		byte_stream_copy_to_uint32_little_endian(
		 &( shell_item_data[ 8 ] ),
		 value_32bit );
		libcnotify_printf(
		 "%s: unknown2\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 &( shell_item_data[ 12 ] ),
		 value_32bit );
		libcnotify_printf(
		 "%s: unknown3\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint32_little_endian(
		 &( shell_item_data[ 16 ] ),
		 value_32bit );
		libcnotify_printf(
		 "%s: unknown4\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 value_32bit );

		byte_stream_copy_to_uint16_little_endian(
		 &( shell_item_data[ 20 ] ),
		 value_16bit );
		libcnotify_printf(
		 "%s: unknown5\t\t\t: 0x%04" PRIx16 "\n",
		 function,
		 value_16bit );

		byte_stream_copy_to_uint16_little_endian(
		 &( shell_item_data[ 22 ] ),
		 value_16bit );
		libcnotify_printf(
		 "%s: unknown6\t\t\t: 0x%04" PRIx16 "\n",
		 function,
		 value_16bit );
	}
#endif
	shell_item_data_offset = 24;

	if( shell_item_data_offset <= ( shell_item_data_size - 2 ) )
	{
		for( string_size = shell_item_data_offset;
		     string_size < shell_item_data_size;
		     string_size += 2 )
		{
			if( shell_item_data[ string_size ] == 0 )
			{
				string_size += 2;

				break;
			}
		}
		string_size -= shell_item_data_offset;

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
			result = libuna_utf16_string_size_from_utf16_stream(
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_size,
				  LIBUNA_ENDIAN_LITTLE,
				  &value_string_size,
				  error );
#else
			result = libuna_utf8_string_size_from_utf16_stream(
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_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 value string.",
				 function );

				goto on_error;
			}
			if( value_string_size > (size_t) ( SSIZE_MAX / sizeof( libcstring_system_character_t ) ) )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
				 "%s: invalid value 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 value 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,
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_size,
				  LIBUNA_ENDIAN_LITTLE,
				  error );
#else
			result = libuna_utf8_string_copy_from_utf16_stream(
				  (libuna_utf8_character_t *) value_string,
				  value_string_size,
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_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 value string.",
				 function );

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

			memory_free(
			 value_string );

			value_string = NULL;
		}
#endif
		shell_item_data_offset += string_size;
	}
	if( shell_item_data_offset <= ( shell_item_data_size - 2 ) )
	{
		for( string_size = shell_item_data_offset;
		     string_size < shell_item_data_size;
		     string_size += 2 )
		{
			if( shell_item_data[ string_size ] == 0 )
			{
				string_size += 2;

				break;
			}
		}
		string_size -= shell_item_data_offset;

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
			result = libuna_utf16_string_size_from_utf16_stream(
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_size,
				  LIBUNA_ENDIAN_LITTLE,
				  &value_string_size,
				  error );
#else
			result = libuna_utf8_string_size_from_utf16_stream(
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_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 value string.",
				 function );

				goto on_error;
			}
			if( value_string_size > (size_t) ( SSIZE_MAX / sizeof( libcstring_system_character_t ) ) )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
				 "%s: invalid value 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 value 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,
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_size,
				  LIBUNA_ENDIAN_LITTLE,
				  error );
#else
			result = libuna_utf8_string_copy_from_utf16_stream(
				  (libuna_utf8_character_t *) value_string,
				  value_string_size,
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_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 value string.",
				 function );

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

			memory_free(
			 value_string );

			value_string = NULL;
		}
#endif
		shell_item_data_offset += string_size;
	}
	if( shell_item_data_offset <= ( shell_item_data_size - 2 ) )
	{
		for( string_size = shell_item_data_offset;
		     string_size < shell_item_data_size;
		     string_size += 2 )
		{
			if( shell_item_data[ string_size ] == 0 )
			{
				string_size += 2;

				break;
			}
		}
		string_size -= shell_item_data_offset;

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
			result = libuna_utf16_string_size_from_utf16_stream(
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_size,
				  LIBUNA_ENDIAN_LITTLE,
				  &value_string_size,
				  error );
#else
			result = libuna_utf8_string_size_from_utf16_stream(
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_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 value string.",
				 function );

				goto on_error;
			}
			if( value_string_size > (size_t) ( SSIZE_MAX / sizeof( libcstring_system_character_t ) ) )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
				 "%s: invalid value 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 value 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,
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_size,
				  LIBUNA_ENDIAN_LITTLE,
				  error );
#else
			result = libuna_utf8_string_copy_from_utf16_stream(
				  (libuna_utf8_character_t *) value_string,
				  value_string_size,
				  &( shell_item_data[ shell_item_data_offset ] ),
				  string_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 value string.",
				 function );

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

			memory_free(
			 value_string );

			value_string = NULL;
		}
#endif
		shell_item_data_offset += string_size;
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "\n" );
	}
#endif
	return( (ssize_t) shell_item_data_offset );

on_error:
#if defined( HAVE_DEBUG_OUTPUT )
	if( value_string != NULL )
	{
		memory_free(
		 value_string );
	}
#endif
	return( -1 );
}
Exemple #25
0
/* Reads a page and its values
 * Returns 1 if successful or -1 on error
 */
int libesedb_page_read(
     libesedb_page_t *page,
     libesedb_io_handle_t *io_handle,
     libbfio_handle_t *file_io_handle,
     off64_t file_offset,
     libcerror_error_t **error )
{
	libcdata_array_t *page_tags_array  = NULL;
	uint8_t *page_values_data          = NULL;
	static char *function              = "libesedb_page_read";
	size_t page_values_data_offset     = 0;
	size_t page_values_data_size       = 0;
	ssize_t read_count                 = 0;
	uint32_t calculated_ecc32_checksum = 0;
	uint32_t calculated_page_number    = 0;
	uint32_t calculated_xor32_checksum = 0;
	uint32_t stored_ecc32_checksum     = 0;
	uint32_t stored_page_number        = 0;
	uint32_t stored_xor32_checksum     = 0;
	uint16_t available_data_size       = 0;
	uint16_t available_page_tag        = 0;

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

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

		return( -1 );
	}
	if( page->data != NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_RUNTIME,
		 LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET,
		 "%s: invalid page data already set.",
		 function );

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

		return( -1 );
	}
	calculated_page_number = (uint32_t) ( ( file_offset - io_handle->page_size ) / io_handle->page_size );

	page->offset = file_offset;

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

		goto on_error;
	}
	page->data = (uint8_t *) memory_allocate(
	                          (size_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 page data.",
		 function );

		goto on_error;
	}
	page->data_size = (size_t) io_handle->page_size;

	read_count = libbfio_handle_read_buffer(
	              file_io_handle,
	              page->data,
	              page->data_size,
	              error );

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

		goto on_error;
	}
	page_values_data      = page->data;
	page_values_data_size = page->data_size;

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: page header:\n",
		 function );
		libcnotify_print_data(
		 page_values_data,
		 sizeof( esedb_page_header_t ),
		 0 );
	}
#endif
	page->page_number = calculated_page_number;

	byte_stream_copy_to_uint16_little_endian(
	 ( (esedb_page_header_t *) page_values_data )->available_data_size,
	 available_data_size );

	byte_stream_copy_to_uint32_little_endian(
	 ( (esedb_page_header_t *) page_values_data )->previous_page,
	 page->previous_page_number );
	byte_stream_copy_to_uint32_little_endian(
	 ( (esedb_page_header_t *) page_values_data )->next_page,
	 page->next_page_number );
	byte_stream_copy_to_uint32_little_endian(
	 ( (esedb_page_header_t *) page_values_data )->father_data_page_object_identifier,
	 page->father_data_page_object_identifier );

	byte_stream_copy_to_uint16_little_endian(
	 ( (esedb_page_header_t *) page_values_data )->available_page_tag,
	 available_page_tag );

	byte_stream_copy_to_uint32_little_endian(
	 ( (esedb_page_header_t *) page_values_data )->page_flags,
	 page->flags );

	/* Make sure to read after the page flags
	 */
	if( ( io_handle->format_revision >= LIBESEDB_FORMAT_REVISION_EXTENDED_PAGE_HEADER )
	 && ( io_handle->page_size >= 16384 ) )
	{
		/* TODO handle checksum */
	}
	else
	{
		byte_stream_copy_to_uint32_little_endian(
		 ( (esedb_page_header_t *) page_values_data )->xor_checksum,
		 stored_xor32_checksum );

		if( ( io_handle->format_revision >= LIBESEDB_FORMAT_REVISION_NEW_RECORD_FORMAT )
		 && ( ( page->flags & LIBESEDB_PAGE_FLAG_IS_NEW_RECORD_FORMAT ) != 0 ) )
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (esedb_page_header_t *) page_values_data )->ecc_checksum,
			 stored_ecc32_checksum );
		}
		else
		{
			byte_stream_copy_to_uint32_little_endian(
			 ( (esedb_page_header_t *) page_values_data )->page_number,
			 stored_page_number );
		}
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: current page number\t\t\t\t\t: %" PRIu32 "\n",
		 function,
		 calculated_page_number );

		if( ( io_handle->format_revision >= LIBESEDB_FORMAT_REVISION_EXTENDED_PAGE_HEADER )
		 && ( io_handle->page_size >= 16384 ) )
		{
			/* TODO handle checksum */

			byte_stream_copy_to_uint64_little_endian(
			 page_values_data,
			 value_64bit );
			libcnotify_printf(
			 "%s: checksum\t\t\t\t\t\t: 0x%08" PRIx64 "\n",
			 function,
			 value_64bit );
		}
		else
		{
			libcnotify_printf(
			 "%s: XOR checksum\t\t\t\t\t: 0x%08" PRIx32 "\n",
			 function,
			 stored_xor32_checksum );

			if( ( io_handle->format_revision >= LIBESEDB_FORMAT_REVISION_NEW_RECORD_FORMAT )
			 && ( ( page->flags & LIBESEDB_PAGE_FLAG_IS_NEW_RECORD_FORMAT ) != 0 ) )
			{
				libcnotify_printf(
				 "%s: ECC checksum\t\t\t\t\t: 0x%08" PRIx32 "\n",
				 function,
				 stored_ecc32_checksum );
			}
			else
			{
				libcnotify_printf(
				 "%s: page number\t\t\t\t\t\t: %" PRIu32 "\n",
				 function,
				 stored_page_number );
			}
		}
		libcnotify_printf(
		 "%s: database modification time:\n",
		 function );
		libcnotify_print_data(
		 ( (esedb_page_header_t *) page_values_data )->database_modification_time,
		 8,
		 0 );

		libcnotify_printf(
		 "%s: previous page number\t\t\t\t: %" PRIu32 "\n",
		 function,
		 page->previous_page_number );
		libcnotify_printf(
		 "%s: next page number\t\t\t\t\t: %" PRIu32 "\n",
		 function,
		 page->next_page_number );
		libcnotify_printf(
		 "%s: father data page (FDP) object identifier\t\t: %" PRIu32 "\n",
		 function,
		 page->father_data_page_object_identifier );

		libcnotify_printf(
		 "%s: available data size\t\t\t\t\t: %" PRIu32 "\n",
		 function,
		 available_data_size );

		byte_stream_copy_to_uint16_little_endian(
		 ( (esedb_page_header_t *) page_values_data )->available_uncommitted_data_size,
		 value_16bit );
		libcnotify_printf(
		 "%s: available uncommitted data size\t\t\t: %" PRIu16 "\n",
		 function,
		 value_16bit );

		byte_stream_copy_to_uint16_little_endian(
		 ( (esedb_page_header_t *) page_values_data )->available_data_offset,
		 value_16bit );
		libcnotify_printf(
		 "%s: available data offset\t\t\t\t: %" PRIu16 "\n",
		 function,
		 value_16bit );

		libcnotify_printf(
		 "%s: available page tag\t\t\t\t\t: %" PRIu32 "\n",
		 function,
		 available_page_tag );

		libcnotify_printf(
		 "%s: page flags\t\t\t\t\t\t: 0x%08" PRIx32 "\n",
		 function,
		 page->flags );
		libesedb_debug_print_page_flags(
		 page->flags );
		libcnotify_printf(
		 "\n" );
	}
#endif
	/* TODO for now don't bother calculating a checksum for uninitialized pages */

	if( ( page_values_data[ 0 ] != 0 )
	 || ( page_values_data[ 1 ] != 0 )
	 || ( page_values_data[ 2 ] != 0 )
	 || ( page_values_data[ 3 ] != 0 ) )
	{
		if( ( io_handle->format_revision >= LIBESEDB_FORMAT_REVISION_EXTENDED_PAGE_HEADER )
		 && ( io_handle->page_size >= 16384 ) )
		{
			/* TODO handle checksum */
		}
		else if( ( io_handle->format_revision >= LIBESEDB_FORMAT_REVISION_NEW_RECORD_FORMAT )
		      && ( ( page->flags & LIBESEDB_PAGE_FLAG_IS_NEW_RECORD_FORMAT ) != 0 ) )
		{
			if( libesedb_checksum_calculate_little_endian_ecc32(
			     &calculated_ecc32_checksum,
			     &calculated_xor32_checksum,
			     page_values_data,
			     page_values_data_size,
			     8,
			     calculated_page_number,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
				 "%s: unable to calculate ECC-32 and XOR-32 checksum.",
				 function );

				goto on_error;
			}
		}
		else
		{
			if( libesedb_checksum_calculate_little_endian_xor32(
			     &calculated_xor32_checksum,
			     &( page_values_data[ 4 ] ),
			     page_values_data_size - 4,
			     0x89abcdef,
			     error ) != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE,
				 "%s: unable to calculate XOR-32 checksum.",
				 function );

				goto on_error;
			}
		}
		if( stored_xor32_checksum != calculated_xor32_checksum )
		{
#ifdef TODO
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_INPUT,
			 LIBCERROR_INPUT_ERROR_CRC_MISMATCH,
			 "%s: mismatch in page XOR-32 checksum ( 0x%08" PRIx32 " != 0x%08" PRIx32 " ).",
			 function,
			 stored_xor32_checksum,
			 calculated_xor32_checksum );

			goto on_error;
#else
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: mismatch in page XOR-32 checksum ( 0x%08" PRIx32 " != 0x%08" PRIx32 " ).\n",
				 function,
				 stored_xor32_checksum,
				 calculated_xor32_checksum );
			}
#endif
		}
		if( stored_ecc32_checksum != calculated_ecc32_checksum )
		{
#ifdef TODO
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_INPUT,
			 LIBCERROR_INPUT_ERROR_CRC_MISMATCH,
			 "%s: mismatch in page ECC-32 checksum ( 0x%08" PRIx32 " != 0x%08" PRIx32 " ).",
			 function,
			 stored_ecc32_checksum,
			 calculated_ecc32_checksum );

			goto on_error;
#else
			if( libcnotify_verbose != 0 )
			{
				libcnotify_printf(
				 "%s: mismatch in page ECC-32 checksum ( 0x%08" PRIx32 " != 0x%08" PRIx32 " ).\n",
				 function,
				 stored_ecc32_checksum,
				 calculated_ecc32_checksum );
			}
#endif
		}
	}
	page_values_data        += sizeof( esedb_page_header_t );
	page_values_data_size   -= sizeof( esedb_page_header_t );
	page_values_data_offset += sizeof( esedb_page_header_t );

	if( ( io_handle->format_revision >= LIBESEDB_FORMAT_REVISION_EXTENDED_PAGE_HEADER )
	 && ( io_handle->page_size >= 16384 ) )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: extended page header:\n",
			 function );
			libcnotify_print_data(
			 page_values_data,
			 40,
			 0 );
		}
#endif
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			byte_stream_copy_to_uint64_little_endian(
			 ( (esedb_extended_page_header_t *) page_values_data )->checksum1,
			 value_64bit );
			libcnotify_printf(
			 "%s: checksum1\t\t\t\t\t\t: 0x%08" PRIx64 "\n",
			 function,
			 value_64bit );

			byte_stream_copy_to_uint64_little_endian(
			 ( (esedb_extended_page_header_t *) page_values_data )->checksum2,
			 value_64bit );
			libcnotify_printf(
			 "%s: checksum2\t\t\t\t\t\t: 0x%08" PRIx64 "\n",
			 function,
			 value_64bit );

			byte_stream_copy_to_uint64_little_endian(
			 ( (esedb_extended_page_header_t *) page_values_data )->checksum3,
			 value_64bit );
			libcnotify_printf(
			 "%s: checksum3\t\t\t\t\t\t: 0x%08" PRIx64 "\n",
			 function,
			 value_64bit );

			byte_stream_copy_to_uint64_little_endian(
			 ( (esedb_extended_page_header_t *) page_values_data )->page_number,
			 value_64bit );
			libcnotify_printf(
			 "%s: page number\t\t\t\t\t\t: %" PRIu64 "\n",
			 function,
			 value_64bit );

			libcnotify_printf(
			 "%s: unknown1:\n",
			 function );
			libcnotify_print_data(
			 ( (esedb_extended_page_header_t *) page_values_data )->unknown1,
			 8,
			 0 );
		}
#endif
		page_values_data        += sizeof( esedb_extended_page_header_t );
		page_values_data_size   -= sizeof( esedb_extended_page_header_t );
		page_values_data_offset += sizeof( esedb_extended_page_header_t );
	}
	if( available_page_tag > 0 )
	{
		/* Create the page tags array
		 */
		if( libcdata_array_initialize(
		     &page_tags_array,
		     0,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_INITIALIZE_FAILED,
			 "%s: unable to create page tags array.",
			 function );

			goto on_error;
		}
		if( libesedb_page_read_tags(
		     page_tags_array,
		     io_handle,
		     available_page_tag,
		     page->data,
		     page->data_size,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read page tags.",
			 function );

			goto on_error;
		}
		/* The offsets in the page tags are relative after the page header
		 */
		if( libesedb_page_read_values(
		     page,
		     io_handle,
		     page_tags_array,
		     page_values_data,
		     page_values_data_size,
		     page_values_data_offset,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_IO,
			 LIBCERROR_IO_ERROR_READ_FAILED,
			 "%s: unable to read page values.",
			 function );

			goto on_error;
		}
		if( libcdata_array_free(
		     &page_tags_array,
		     (int (*)(intptr_t **, libcerror_error_t **)) &libesedb_page_tags_value_free,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
			 "%s: unable to free the page tags array.",
			 function );

			goto on_error;
		}
	}
	return( 1 );

on_error:
	if( page_tags_array != NULL )
	{
		libcdata_array_free(
		 &page_tags_array,
		 (int (*)(intptr_t **, libcerror_error_t **)) &libesedb_page_tags_value_free,
		 NULL );
	}
	if( page->data != NULL )
	{
		memory_free(
		 page->data );

		page->data = NULL;
	}
	return( -1 );
}
/* Reads the volume values
 * Returns the number of bytes read, 0 if not able to read or -1 on error
 */
ssize_t libfwsi_volume_values_read(
         libfwsi_volume_values_t *volume_values,
         const uint8_t *shell_item_data,
         size_t shell_item_data_size,
         int ascii_codepage,
         libcerror_error_t **error )
{
	static char *function                       = "libfwsi_volume_values_read";
	size_t shell_item_data_offset               = 0;
	size_t string_size                          = 0;
	uint8_t class_type_indicator                = 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;
	uint16_t value_16bit                        = 0;
	int result                                  = 0;
#endif

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

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

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

		return( -1 );
	}
	/* Do not try to parse unsupported shell item data sizes
	 */
	if( shell_item_data_size < 20 )
	{
		return( 0 );
	}
	/* Do not try to parse unknown class type indicators
	 */
	if( ( shell_item_data[ 2 ] != 0x23 )
	 && ( shell_item_data[ 2 ] != 0x25 )
	 && ( shell_item_data[ 2 ] != 0x29 )
	 && ( shell_item_data[ 2 ] != 0x2a )
	 && ( shell_item_data[ 2 ] != 0x2e )
	 && ( shell_item_data[ 2 ] != 0x2f ) )
	{
		return( 0 );
	}
	class_type_indicator = shell_item_data[ 2 ];

	volume_values->ascii_codepage = ascii_codepage;

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

			goto on_error;
		}
	}
#endif
	if( class_type_indicator == 0x2e )
	{
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			libcnotify_printf(
			 "%s: unknown1\t\t\t\t\t: 0x%02" PRIx8 "\n",
			 function,
			 shell_item_data[ 3 ] );
		}
#endif
		volume_values->has_name = 0;

		if( memory_copy(
		     volume_values->identifier,
		     &( shell_item_data[ 4 ] ),
		     16 ) == NULL )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_MEMORY,
			 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
			 "%s: unable to copy volume identifier.",
			 function );

			goto on_error;
		}
#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
			if( libfguid_identifier_copy_from_byte_stream(
			     guid,
			     volume_values->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_UPPER_CASE | LIBFGUID_STRING_FORMAT_FLAG_USE_SURROUNDING_BRACES,
				  error );
#else
			result = libfguid_identifier_copy_to_utf8_string(
				  guid,
				  (uint8_t *) guid_string,
				  48,
				  LIBFGUID_STRING_FORMAT_FLAG_USE_UPPER_CASE | LIBFGUID_STRING_FORMAT_FLAG_USE_SURROUNDING_BRACES,
				  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: shell folder identifier\t\t\t: %" PRIs_LIBCSTRING_SYSTEM "\n",
			 function,
			 guid_string );
			libcnotify_printf(
			 "%s: shell folder name\t\t\t\t: %s\n",
			 function,
			 libfwsi_shell_folder_identifier_get_name(
			  volume_values->identifier ) );
		}
#endif
		shell_item_data_offset = 20;
	}
	else
	{
		/* Do not try to parse unsupported shell item data sizes
		 */
		if( shell_item_data_size < 25 )
		{
			return( 0 );
		}
		volume_values->has_name = 1;

		if( memory_copy(
		     volume_values->name,
		     &( shell_item_data[ 3 ] ),
		     20 ) == NULL )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_MEMORY,
			 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
			 "%s: unable to copy volume name.",
			 function );

			goto on_error;
		}
		for( string_size = 0;
		     string_size < 20;
		     string_size++ )
		{
			if( volume_values->name[ string_size ] == 0 )
			{
				break;
			}
		}
		volume_values->name_size = string_size;

#if defined( HAVE_DEBUG_OUTPUT )
		if( libcnotify_verbose != 0 )
		{
#if defined( LIBCSTRING_HAVE_WIDE_SYSTEM_CHARACTER )
			result = libuna_utf16_string_size_from_byte_stream(
				  volume_values->name,
				  volume_values->name_size,
				  volume_values->ascii_codepage,
				  &value_string_size,
				  error );
#else
			result = libuna_utf8_string_size_from_byte_stream(
				  volume_values->name,
				  volume_values->name_size,
				  volume_values->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 volume name string.",
				 function );

				goto on_error;
			}
			if( value_string_size > (size_t) ( SSIZE_MAX / sizeof( libcstring_system_character_t ) ) )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM,
				 "%s: invalid volume name 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 volume name 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,
				  volume_values->name,
				  volume_values->name_size,
				  volume_values->ascii_codepage,
				  error );
#else
			result = libuna_utf8_string_copy_from_byte_stream(
				  (libuna_utf8_character_t *) value_string,
				  value_string_size,
				  volume_values->name,
				  volume_values->name_size,
				  volume_values->ascii_codepage,
				  error );
#endif
			if( result != 1 )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_RUNTIME,
				 LIBCERROR_RUNTIME_ERROR_SET_FAILED,
				 "%s: unable to set volume name string.",
				 function );

				goto on_error;
			}
			libcnotify_printf(
			 "%s: volume name\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 )
		{
			byte_stream_copy_to_uint16_little_endian(
			 &( shell_item_data[ 23 ] ),
			 value_16bit );
			libcnotify_printf(
			 "%s: unknown2\t\t\t\t\t: 0x%04" PRIx16 "\n",
			 function,
			 value_16bit );
		}
#endif
		shell_item_data_offset = 25;

		if( shell_item_data_offset <= ( shell_item_data_size - 16 ) )
		{
			if( memory_copy(
			     volume_values->shell_folder_identifier,
			     &( shell_item_data[ shell_item_data_offset ] ),
			     16 ) == NULL )
			{
				libcerror_error_set(
				 error,
				 LIBCERROR_ERROR_DOMAIN_MEMORY,
				 LIBCERROR_MEMORY_ERROR_COPY_FAILED,
				 "%s: unable to copy shell folder identifier.",
				 function );

				goto on_error;
			}
#if defined( HAVE_DEBUG_OUTPUT )
			if( libcnotify_verbose != 0 )
			{
				if( libfguid_identifier_copy_from_byte_stream(
				     guid,
				     volume_values->shell_folder_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_UPPER_CASE | LIBFGUID_STRING_FORMAT_FLAG_USE_SURROUNDING_BRACES,
					  error );
#else
				result = libfguid_identifier_copy_to_utf8_string(
					  guid,
					  (uint8_t *) guid_string,
					  48,
					  LIBFGUID_STRING_FORMAT_FLAG_USE_UPPER_CASE | LIBFGUID_STRING_FORMAT_FLAG_USE_SURROUNDING_BRACES,
					  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: shell folder identifier\t\t\t: %" PRIs_LIBCSTRING_SYSTEM "\n",
				 function,
				 guid_string );

				libcnotify_printf(
				 "%s: shell folder name\t\t\t\t: %s\n",
				 function,
				 libfwsi_shell_folder_identifier_get_name(
				  &( shell_item_data[ shell_item_data_offset ] ) ) );
			}
#endif
			shell_item_data_offset += 16;
		}
	}
#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		if( libfguid_identifier_free(
		     &guid,
		     error ) != 1 )
		{
			libcerror_error_set(
			 error,
			 LIBCERROR_ERROR_DOMAIN_RUNTIME,
			 LIBCERROR_RUNTIME_ERROR_FINALIZE_FAILED,
			 "%s: unable to free GUID.",
			 function );

			goto on_error;
		}
		libcnotify_printf(
		 "\n" );
	}
#endif
	return( (ssize_t) shell_item_data_offset );

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 property set from the property set stream
 * Returns 1 if successful or -1 on error
 */
int libolecf_property_set_read(
     libolecf_property_set_t *property_set,
     libolecf_io_handle_t *io_handle,
     libolecf_item_t *property_set_stream,
     libcerror_error_t **error )
{
	olecf_property_set_header_t property_set_header;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_64:
			character_limit = 64;
			break;

		case LIBUNA_BASE16_VARIANT_CHARACTER_LIMIT_76:
			character_limit = 76;
			break;

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

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

		case LIBUNA_BASE16_VARIANT_CASE_MIXED:
			character_case = LIBUNA_CASE_MIXED;
			break;

		case LIBUNA_BASE16_VARIANT_CASE_UPPER:
			character_case = LIBUNA_CASE_UPPER;
			break;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		return( -1 );
	}
	base16_stream_index = 0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

			return( -1 );
		}
	}
	return( 1 );
}
Exemple #29
0
/* Reads the extent data
 * Returns 1 if successful or -1 on error
 */
int libfsext_extent_read_data(
     libfsext_extent_t *extent,
     const uint8_t *data,
     size_t data_size,
     libcerror_error_t **error )
{
	static char *function                = "libfsext_extent_read_data";
	uint32_t physical_block_number_upper = 0;
	uint16_t physical_block_number_lower = 0;

	if( extent == NULL )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
		 "%s: invalid extent.",
		 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 < sizeof( fsext_extent_ext4_t ) )
	{
		libcerror_error_set(
		 error,
		 LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
		 LIBCERROR_ARGUMENT_ERROR_UNSUPPORTED_VALUE,
		 "%s: unsupported data size.",
		 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: extent data:\n",
		 function );
		libcnotify_print_data(
		 data,
		 data_size,
		 0 );
	}
#endif
	byte_stream_copy_to_uint32_little_endian(
	 ( (fsext_extent_ext4_t *) data )->logical_block_number,
	 extent->logical_block_number );

	byte_stream_copy_to_uint16_little_endian(
	 ( (fsext_extent_ext4_t *) data )->number_of_blocks,
	 extent->number_of_blocks );

	byte_stream_copy_to_uint16_little_endian(
	 ( (fsext_extent_ext4_t *) data )->physical_block_number_upper,
	 physical_block_number_upper );

	byte_stream_copy_to_uint32_little_endian(
	 ( (fsext_extent_ext4_t *) data )->physical_block_number_lower,
	 physical_block_number_lower );

#if defined( HAVE_DEBUG_OUTPUT )
	if( libcnotify_verbose != 0 )
	{
		libcnotify_printf(
		 "%s: logical block number\t\t\t\t: %" PRIu32 "\n",
		 function,
		 extent->logical_block_number );

		libcnotify_printf(
		 "%s: number of blocks\t\t\t\t: %" PRIu16 "\n",
		 function,
		 extent->number_of_blocks );

		libcnotify_printf(
		 "%s: physical block number (upper)\t\t: %" PRIu16 "\n",
		 function,
		 physical_block_number_upper );

		libcnotify_printf(
		 "%s: physical block number (lower)\t\t: %" PRIu32 "\n",
		 function,
		 physical_block_number_lower );

		libcnotify_printf(
		 "\n" );
	}
#endif /* defined( HAVE_DEBUG_OUTPUT ) */

	extent->physical_block_number = ( (uint64_t) physical_block_number_upper << 32 ) | physical_block_number_lower;

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