/* 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, §ion_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, §ion_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, §ions_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 ); }
/* Converts the value data into a 32-bit value * Returns 1 if successful or -1 on error */ int libregf_value_type_copy_to_32bit( uint8_t *value_data, size_t value_data_size, uint8_t byte_order, uint32_t *value_32bit, libcerror_error_t **error ) { static char *function = "libregf_value_type_copy_to_32bit"; if( value_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid value data.", function ); return( -1 ); } if( value_32bit == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid value 32-bit.", function ); return( -1 ); } /* The value data size of a 32-bit value is 4 */ if( value_data_size != 4 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid value data size value out of bounds.", function ); return( -1 ); } if( ( byte_order != LIBREGF_ENDIAN_BIG ) && ( byte_order != LIBREGF_ENDIAN_LITTLE ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, "%s: unsupported byte order: 0x%02" PRIx8 ".", function, byte_order ); return( -1 ); } if( byte_order == LIBREGF_ENDIAN_BIG ) { byte_stream_copy_to_uint32_big_endian( value_data, *value_32bit ); } else { byte_stream_copy_to_uint32_little_endian( value_data, *value_32bit ); } return( 1 ); }
/* Reads a B-tree file node descriptor * Returns 1 if successful or -1 on error */ int libfshfs_btree_file_read_node_descriptor( const uint8_t *data, size_t data_size, uint16_t *number_of_records, libcerror_error_t **error ) { static char *function = "libfshfs_btree_file_read_node_descriptor"; uint32_t next_node_number = 0; uint32_t previous_node_number = 0; #if defined( HAVE_DEBUG_OUTPUT ) uint16_t value_16bit = 0; #endif if( data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: invalid data.", function ); return( -1 ); } if( ( data_size < sizeof( fshfs_btree_node_descriptor_t ) ) || ( data_size > (size_t) SSIZE_MAX ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid data size value out of bounds.", function ); return( -1 ); } if( number_of_records == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_MISSING, "%s: invalid number of records.", function ); return( -1 ); } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: B-tree node descriptor data:\n", function ); libcnotify_print_data( (uint8_t *) data, sizeof( fshfs_btree_node_descriptor_t ), LIBCNOTIFY_PRINT_DATA_FLAG_GROUP_DATA ); } #endif byte_stream_copy_to_uint32_big_endian( ( (fshfs_btree_node_descriptor_t *) data )->next_node_number, next_node_number ); byte_stream_copy_to_uint32_big_endian( ( (fshfs_btree_node_descriptor_t *) data )->previous_node_number, previous_node_number ); byte_stream_copy_to_uint16_big_endian( ( (fshfs_btree_node_descriptor_t *) data )->number_of_records, *number_of_records ); #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: next node number\t\t: %" PRIu32 "\n", function, next_node_number ); libcnotify_printf( "%s: previous node number\t\t: %" PRIu32 "\n", function, previous_node_number ); libcnotify_printf( "%s: node type\t\t\t: %" PRIi8 " (%s)\n", function, ( (fshfs_btree_node_descriptor_t *) data )->node_type, libfshfs_debug_print_btree_node_type( ( (fshfs_btree_node_descriptor_t *) data )->node_type ) ); libcnotify_printf( "%s: node level\t\t\t: %" PRIi8 "\n", function, ( (fshfs_btree_node_descriptor_t *) data )->node_level ); libcnotify_printf( "%s: number of records\t\t: %" PRIu16 "\n", function, *number_of_records ); byte_stream_copy_to_uint16_big_endian( ( (fshfs_btree_node_descriptor_t *) data )->unknown1, value_16bit ); libcnotify_printf( "%s: unknown1\t\t\t: 0x%04" PRIx16 "\n", function, value_16bit ); libcnotify_printf( "\n", function ); } #endif return( 1 ); }
/* Reads the file header * Returns 1 if successful or -1 on error */ int libqcow_io_handle_read_file_header( libqcow_io_handle_t *io_handle, libbfio_handle_t *file_io_handle, uint32_t *encryption_method, libcerror_error_t **error ) { uint8_t *file_header_data = NULL; static char *function = "libqcow_io_handle_read_file_header"; size_t read_size = 512; ssize_t read_count = 0; uint64_t backing_filename_offset = 0; uint32_t number_of_level1_table_references = 0; #if defined( HAVE_DEBUG_OUTPUT ) uint64_t value_64bit = 0; uint32_t value_32bit = 0; uint16_t value_16bit = 0; #endif if( io_handle == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid IO handle.", function ); return( -1 ); } if( io_handle->backing_filename != NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_ALREADY_SET, "%s: invalid IO handle - backing filename value already set.", function ); return( -1 ); } if( encryption_method == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_ARGUMENTS, LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE, "%s: invalid encryption method.", function ); return( -1 ); } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: reading file header at offset: 0 (0x00000000)\n", function ); } #endif if( libbfio_handle_seek_offset( file_io_handle, 0, SEEK_SET, error ) == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_SEEK_FAILED, "%s: unable to seek file header offset: 0.", function ); goto on_error; } file_header_data = (uint8_t *) memory_allocate( sizeof( uint8_t ) * read_size ); if( file_header_data == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_INSUFFICIENT, "%s: unable to create file header data.", function ); goto on_error; } read_count = libbfio_handle_read_buffer( file_io_handle, file_header_data, read_size, error ); if( read_count != (ssize_t) read_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_READ_FAILED, "%s: unable to read file header.", function ); goto on_error; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: file header data:\n", function ); libcnotify_print_data( file_header_data, sizeof( qcow_file_header_v1_t ), 0 ); } #endif if( memory_compare( ( (qcow_file_header_v1_t *) file_header_data )->signature, qcow_file_signature, 4 ) != 0 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, "%s: unsupported file signature.", function ); goto on_error; } byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->format_version, io_handle->format_version ); byte_stream_copy_to_uint64_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->backing_filename_offset, backing_filename_offset ); byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->backing_filename_size, io_handle->backing_filename_size ); #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->signature, value_32bit ); libcnotify_printf( "%s: signature\t\t\t\t: 0x%08" PRIx32 "\n", function, value_32bit ); libcnotify_printf( "%s: format version\t\t\t: %" PRIu32 "\n", function, io_handle->format_version ); libcnotify_printf( "%s: backing filename offset\t\t: %" PRIu32 "\n", function, backing_filename_offset ); libcnotify_printf( "%s: backing filename size\t\t: %" PRIu32 "\n", function, io_handle->backing_filename_size ); } #endif if( ( io_handle->format_version != 1 ) && ( io_handle->format_version != 2 ) && ( io_handle->format_version != 3 ) ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_UNSUPPORTED_VALUE, "%s: unsupported format version: %" PRIu32 ".", function, io_handle->format_version ); goto on_error; } if( io_handle->format_version == 1 ) { byte_stream_copy_to_uint64_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->media_size, io_handle->media_size ); io_handle->number_of_cluster_block_bits = (uint32_t) ( (qcow_file_header_v1_t *) file_header_data )->number_of_cluster_block_bits; io_handle->number_of_level2_table_bits = (uint32_t) ( (qcow_file_header_v1_t *) file_header_data )->number_of_level2_table_bits; byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->encryption_method, *encryption_method ); byte_stream_copy_to_uint64_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->level1_table_offset, io_handle->level1_table_offset ); #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->modification_time, value_32bit ); libcnotify_printf( "%s: modification time\t\t\t: %" PRIu32 "\n", function, value_32bit ); libcnotify_printf( "%s: media size\t\t\t\t: %" PRIu64 "\n", function, io_handle->media_size ); libcnotify_printf( "%s: number of cluster block bits\t: %" PRIu32 "\n", function, io_handle->number_of_cluster_block_bits ); libcnotify_printf( "%s: number of level 2 table bits\t: %" PRIu32 "\n", function, io_handle->number_of_level2_table_bits ); byte_stream_copy_to_uint16_big_endian( ( (qcow_file_header_v1_t *) file_header_data )->unknown1, value_16bit ); libcnotify_printf( "%s: unknown1\t\t\t\t: 0x%04" PRIx16 "\n", function, value_16bit ); libcnotify_printf( "%s: encryption method\t\t\t: %" PRIu32 "\n", function, *encryption_method ); libcnotify_printf( "%s: level 1 table offset\t\t: 0x%08" PRIx64 "\n", function, io_handle->level1_table_offset ); } #endif } else if( ( io_handle->format_version == 2 ) || ( io_handle->format_version == 3 ) ) { byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->number_of_cluster_block_bits, io_handle->number_of_cluster_block_bits ); byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->number_of_level1_table_references, number_of_level1_table_references ); byte_stream_copy_to_uint64_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->level1_table_offset, io_handle->level1_table_offset ); byte_stream_copy_to_uint64_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->media_size, io_handle->media_size ); byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->encryption_method, *encryption_method ); #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: number of cluster block bits\t: %" PRIu32 "\n", function, io_handle->number_of_cluster_block_bits ); libcnotify_printf( "%s: media size\t\t\t\t: %" PRIu64 "\n", function, io_handle->media_size ); libcnotify_printf( "%s: encryption method\t\t\t: %" PRIu32 "\n", function, *encryption_method ); libcnotify_printf( "%s: number of level 1 table references\t: %" PRIu32 "\n", function, number_of_level1_table_references ); libcnotify_printf( "%s: level 1 table offset\t\t: 0x%08" PRIx64 "\n", function, io_handle->level1_table_offset ); byte_stream_copy_to_uint64_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->reference_count_table_offset, value_64bit ); libcnotify_printf( "%s: reference count table offset\t: 0x%08" PRIx64 "\n", function, value_64bit ); byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->reference_count_table_clusters, value_32bit ); libcnotify_printf( "%s: reference count table clusters\t: %" PRIu32 "\n", function, value_32bit ); byte_stream_copy_to_uint32_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->number_of_snapshots, value_32bit ); libcnotify_printf( "%s: number of snapshots\t\t\t: %" PRIu32 "\n", function, value_32bit ); byte_stream_copy_to_uint64_big_endian( ( (qcow_file_header_v2_t *) file_header_data )->snapshots_offset, value_64bit ); libcnotify_printf( "%s: snapshots offset\t\t\t: 0x%08" PRIx64 "\n", function, value_64bit ); } #endif } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "\n" ); } #endif memory_free( file_header_data ); file_header_data = NULL; if( io_handle->format_version == 1 ) { io_handle->offset_bit_mask = 0x7fffffffffffffffULL; io_handle->compression_flag_bit_mask = (uint64_t) 1 << 63; io_handle->compression_bit_shift = 63 - io_handle->number_of_cluster_block_bits; } else if( ( io_handle->format_version == 2 ) || ( io_handle->format_version == 3 ) ) { if( io_handle->number_of_cluster_block_bits <= 8 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS, "%s: invalid number of cluster block bits value out of bounds.", function ); goto on_error; } io_handle->number_of_level2_table_bits = io_handle->number_of_cluster_block_bits - 3; io_handle->offset_bit_mask = 0x3fffffffffffffffULL; io_handle->compression_flag_bit_mask = (uint64_t) 1 << 62; io_handle->compression_bit_shift = 62 - ( io_handle->number_of_cluster_block_bits - 8 ); } io_handle->level1_index_bit_shift = io_handle->number_of_cluster_block_bits + io_handle->number_of_level2_table_bits; io_handle->level2_index_bit_mask = ~( (uint64_t) -1 << io_handle->number_of_level2_table_bits ); io_handle->cluster_block_bit_mask = ~( (uint64_t) -1 << io_handle->number_of_cluster_block_bits ); io_handle->compression_bit_mask = ~( (uint64_t) -1 << io_handle->compression_bit_shift ); io_handle->level2_table_size = (size_t) 1 << io_handle->number_of_level2_table_bits; io_handle->cluster_block_size = (size_t) 1 << io_handle->number_of_cluster_block_bits; if( io_handle->format_version == 1 ) { io_handle->level1_table_size = (uint32_t) ( io_handle->cluster_block_size * io_handle->level2_table_size ); if( ( io_handle->media_size % io_handle->level1_table_size ) != 0 ) { io_handle->level1_table_size = (uint32_t) ( ( io_handle->media_size / io_handle->level1_table_size ) + 1 ); } else { io_handle->level1_table_size = (uint32_t) ( io_handle->media_size / io_handle->level1_table_size ); } } else if( ( io_handle->format_version == 2 ) || ( io_handle->format_version == 3 ) ) { io_handle->level1_table_size = number_of_level1_table_references; } io_handle->level1_table_size *= 8; io_handle->level2_table_size *= 8; #if UINT32_MAX > SSIZE_MAX if( io_handle->level1_table_size > (uint32_t) SSIZE_MAX ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_RUNTIME, LIBCERROR_RUNTIME_ERROR_VALUE_EXCEEDS_MAXIMUM, "%s: invalid level 1 table size value exceeds maximum.", function ); goto on_error; } #endif #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: level 1 table size\t\t\t: %" PRIzd "\n", function, io_handle->level1_table_size ); libcnotify_printf( "%s: level 2 table size\t\t\t: %" PRIzd "\n", function, io_handle->level2_table_size ); libcnotify_printf( "%s: cluster block size\t\t\t: %" PRIzd "\n", function, io_handle->cluster_block_size ); } #endif if( ( backing_filename_offset > 0 ) && ( io_handle->backing_filename_size > 0 ) ) { #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: reading backing filename at offset: %" PRIu64 " (0x%08" PRIx64 ")\n", function, backing_filename_offset, backing_filename_offset ); } #endif if( libbfio_handle_seek_offset( file_io_handle, backing_filename_offset, SEEK_SET, error ) == -1 ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_SEEK_FAILED, "%s: unable to seek file header offset: %" PRIu64 ".", function, backing_filename_offset ); goto on_error; } io_handle->backing_filename = (uint8_t *) memory_allocate( sizeof( uint8_t ) * io_handle->backing_filename_size ); if( io_handle->backing_filename == NULL ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_MEMORY, LIBCERROR_MEMORY_ERROR_INSUFFICIENT, "%s: unable to create backing filename.", function ); goto on_error; } read_count = libbfio_handle_read_buffer( file_io_handle, io_handle->backing_filename, io_handle->backing_filename_size, error ); if( read_count != (ssize_t) io_handle->backing_filename_size ) { libcerror_error_set( error, LIBCERROR_ERROR_DOMAIN_IO, LIBCERROR_IO_ERROR_READ_FAILED, "%s: unable to read file header.", function ); goto on_error; } #if defined( HAVE_DEBUG_OUTPUT ) if( libcnotify_verbose != 0 ) { libcnotify_printf( "%s: backing filename data:\n", function ); libcnotify_print_data( io_handle->backing_filename, (size_t) io_handle->backing_filename_size, 0 ); } #endif } return( 1 ); on_error: if( io_handle->backing_filename != NULL ) { memory_free( io_handle->backing_filename ); io_handle->backing_filename = NULL; io_handle->backing_filename_size = 0; } if( file_header_data != NULL ) { memory_free( file_header_data ); } return( -1 ); }